fix baseline build (old cairo) - 'cairo_rectangle_int_t' does not name a type
[LibreOffice.git] / sc / source / core / tool / interpr5.cxx
blob3947ebafc44fe09a2d4969df97f990c5a1552cc1
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <rtl/math.hxx>
21 #include <string.h>
22 #include <math.h>
23 #include <stdio.h>
25 #include <unotools/bootstrap.hxx>
26 #include <officecfg/Office/Common.hxx>
27 #include <svl/zforlist.hxx>
29 #include "interpre.hxx"
30 #include "global.hxx"
31 #include "compiler.hxx"
32 #include "formulacell.hxx"
33 #include "document.hxx"
34 #include "dociter.hxx"
35 #include "scmatrix.hxx"
36 #include "globstr.hrc"
37 #include "cellkeytranslator.hxx"
38 #include "formulagroup.hxx"
40 #include <vector>
42 using ::std::vector;
43 using namespace formula;
45 namespace {
47 struct MatrixAdd : public ::std::binary_function<double,double,double>
49 inline double operator() (const double& lhs, const double& rhs) const
51 return ::rtl::math::approxAdd( lhs,rhs);
55 struct MatrixSub : public ::std::binary_function<double,double,double>
57 inline double operator() (const double& lhs, const double& rhs) const
59 return ::rtl::math::approxSub( lhs,rhs);
63 struct MatrixMul : public ::std::binary_function<double,double,double>
65 inline double operator() (const double& lhs, const double& rhs) const
67 return lhs * rhs;
71 struct MatrixDiv : public ::std::binary_function<double,double,double>
73 inline double operator() (const double& lhs, const double& rhs) const
75 return ScInterpreter::div( lhs,rhs);
79 struct MatrixPow : public ::std::binary_function<double,double,double>
81 inline double operator() (const double& lhs, const double& rhs) const
83 return ::pow( lhs,rhs);
87 // Multiply n x m Mat A with m x l Mat B to n x l Mat R
88 void lcl_MFastMult(ScMatrixRef pA, ScMatrixRef pB, ScMatrixRef pR,
89 SCSIZE n, SCSIZE m, SCSIZE l)
91 double sum;
92 for (SCSIZE row = 0; row < n; row++)
94 for (SCSIZE col = 0; col < l; col++)
95 { // result element(col, row) =sum[ (row of A) * (column of B)]
96 sum = 0.0;
97 for (SCSIZE k = 0; k < m; k++)
98 sum += pA->GetDouble(k,row) * pB->GetDouble(col,k);
99 pR->PutDouble(sum, col, row);
106 double ScInterpreter::ScGetGCD(double fx, double fy)
108 // By ODFF definition GCD(0,a) => a. This is also vital for the code in
109 // ScGCD() to work correctly with a preset fy=0.0
110 if (fy == 0.0)
111 return fx;
112 else if (fx == 0.0)
113 return fy;
114 else
116 double fz = fmod(fx, fy);
117 while (fz > 0.0)
119 fx = fy;
120 fy = fz;
121 fz = fmod(fx, fy);
123 return fy;
127 void ScInterpreter::ScGCD()
129 short nParamCount = GetByte();
130 if ( MustHaveParamCountMin( nParamCount, 1 ) )
132 double fx, fy = 0.0;
133 ScRange aRange;
134 size_t nRefInList = 0;
135 while (!nGlobalError && nParamCount-- > 0)
137 switch (GetStackType())
139 case svDouble :
140 case svString:
141 case svSingleRef:
143 fx = ::rtl::math::approxFloor( GetDouble());
144 if (fx < 0.0)
146 PushIllegalArgument();
147 return;
149 fy = ScGetGCD(fx, fy);
151 break;
152 case svDoubleRef :
153 case svRefList :
155 sal_uInt16 nErr = 0;
156 PopDoubleRef( aRange, nParamCount, nRefInList);
157 double nCellVal;
158 ScValueIterator aValIter( pDok, aRange, mnSubTotalFlags );
159 if (aValIter.GetFirst(nCellVal, nErr))
163 fx = ::rtl::math::approxFloor( nCellVal);
164 if (fx < 0.0)
166 PushIllegalArgument();
167 return;
169 fy = ScGetGCD(fx, fy);
170 } while (nErr == 0 && aValIter.GetNext(nCellVal, nErr));
172 SetError(nErr);
174 break;
175 case svMatrix :
176 case svExternalSingleRef:
177 case svExternalDoubleRef:
179 ScMatrixRef pMat = GetMatrix();
180 if (pMat)
182 SCSIZE nC, nR;
183 pMat->GetDimensions(nC, nR);
184 if (nC == 0 || nR == 0)
185 SetError(errIllegalArgument);
186 else
188 for ( SCSIZE j = 0; j < nC; j++ )
190 for (SCSIZE k = 0; k < nR; ++k)
192 if (!pMat->IsValue(j,k))
194 PushIllegalArgument();
195 return;
197 fx = ::rtl::math::approxFloor( pMat->GetDouble(j,k));
198 if (fx < 0.0)
200 PushIllegalArgument();
201 return;
203 fy = ScGetGCD(fx, fy);
209 break;
210 default : SetError(errIllegalParameter); break;
213 PushDouble(fy);
217 void ScInterpreter:: ScLCM()
219 short nParamCount = GetByte();
220 if ( MustHaveParamCountMin( nParamCount, 1 ) )
222 double fx, fy = 1.0;
223 ScRange aRange;
224 size_t nRefInList = 0;
225 while (!nGlobalError && nParamCount-- > 0)
227 switch (GetStackType())
229 case svDouble :
230 case svString:
231 case svSingleRef:
233 fx = ::rtl::math::approxFloor( GetDouble());
234 if (fx < 0.0)
236 PushIllegalArgument();
237 return;
239 if (fx == 0.0 || fy == 0.0)
240 fy = 0.0;
241 else
242 fy = fx * fy / ScGetGCD(fx, fy);
244 break;
245 case svDoubleRef :
246 case svRefList :
248 sal_uInt16 nErr = 0;
249 PopDoubleRef( aRange, nParamCount, nRefInList);
250 double nCellVal;
251 ScValueIterator aValIter( pDok, aRange, mnSubTotalFlags );
252 if (aValIter.GetFirst(nCellVal, nErr))
256 fx = ::rtl::math::approxFloor( nCellVal);
257 if (fx < 0.0)
259 PushIllegalArgument();
260 return;
262 if (fx == 0.0 || fy == 0.0)
263 fy = 0.0;
264 else
265 fy = fx * fy / ScGetGCD(fx, fy);
266 } while (nErr == 0 && aValIter.GetNext(nCellVal, nErr));
268 SetError(nErr);
270 break;
271 case svMatrix :
272 case svExternalSingleRef:
273 case svExternalDoubleRef:
275 ScMatrixRef pMat = GetMatrix();
276 if (pMat)
278 SCSIZE nC, nR;
279 pMat->GetDimensions(nC, nR);
280 if (nC == 0 || nR == 0)
281 SetError(errIllegalArgument);
282 else
284 for ( SCSIZE j = 0; j < nC; j++ )
286 for (SCSIZE k = 0; k < nR; ++k)
288 if (!pMat->IsValue(j,k))
290 PushIllegalArgument();
291 return;
293 fx = ::rtl::math::approxFloor( pMat->GetDouble(j,k));
294 if (fx < 0.0)
296 PushIllegalArgument();
297 return;
299 if (fx == 0.0 || fy == 0.0)
300 fy = 0.0;
301 else
302 fy = fx * fy / ScGetGCD(fx, fy);
308 break;
309 default : SetError(errIllegalParameter); break;
312 PushDouble(fy);
316 ScMatrixRef ScInterpreter::GetNewMat(SCSIZE nC, SCSIZE nR, bool bEmpty)
318 ScMatrixRef pMat;
319 if (bEmpty)
320 pMat = new ScMatrix(nC, nR);
321 else
322 pMat = new ScMatrix(nC, nR, 0.0);
324 pMat->SetErrorInterpreter( this);
325 // A temporary matrix is mutable and ScMatrix::CloneIfConst() returns the
326 // very matrix.
327 pMat->SetImmutable( false);
328 SCSIZE nCols, nRows;
329 pMat->GetDimensions( nCols, nRows);
330 if ( nCols != nC || nRows != nR )
331 { // arbitray limit of elements exceeded
332 SetError( errStackOverflow);
333 pMat.reset();
335 return pMat;
338 ScMatrixRef ScInterpreter::CreateMatrixFromDoubleRef( const FormulaToken* pToken,
339 SCCOL nCol1, SCROW nRow1, SCTAB nTab1,
340 SCCOL nCol2, SCROW nRow2, SCTAB nTab2 )
342 if (nTab1 != nTab2 || nGlobalError)
344 // Not a 2D matrix.
345 SetError(errIllegalParameter);
346 return NULL;
349 SCSIZE nMatCols = static_cast<SCSIZE>(nCol2 - nCol1 + 1);
350 SCSIZE nMatRows = static_cast<SCSIZE>(nRow2 - nRow1 + 1);
352 if (nMatRows * nMatCols > ScMatrix::GetElementsMax())
354 SetError(errStackOverflow);
355 return NULL;
358 ScTokenMatrixMap::const_iterator aIter;
359 if (pTokenMatrixMap && ((aIter = pTokenMatrixMap->find( pToken))
360 != pTokenMatrixMap->end()))
362 return (*aIter).second.get()->GetMatrix();
365 ScMatrixRef pMat = GetNewMat( nMatCols, nMatRows, true);
366 if (!pMat || nGlobalError)
367 return NULL;
369 pDok->FillMatrix(*pMat, nTab1, nCol1, nRow1, nCol2, nRow2);
371 if (pTokenMatrixMap)
372 pTokenMatrixMap->insert( ScTokenMatrixMap::value_type(
373 pToken, new ScMatrixToken( pMat)));
375 return pMat;
378 ScMatrixRef ScInterpreter::GetMatrix()
380 ScMatrixRef pMat = NULL;
381 switch (GetRawStackType())
383 case svSingleRef :
385 ScAddress aAdr;
386 PopSingleRef( aAdr );
387 pMat = GetNewMat(1, 1);
388 if (pMat)
390 ScRefCellValue aCell;
391 aCell.assign(*pDok, aAdr);
392 if (aCell.hasEmptyValue())
393 pMat->PutEmpty(0, 0);
394 else if (aCell.hasNumeric())
395 pMat->PutDouble(GetCellValue(aAdr, aCell), 0);
396 else
398 svl::SharedString aStr;
399 GetCellString(aStr, aCell);
400 pMat->PutString(aStr, 0);
404 break;
405 case svDoubleRef:
407 SCCOL nCol1, nCol2;
408 SCROW nRow1, nRow2;
409 SCTAB nTab1, nTab2;
410 const formula::FormulaToken* p = sp ? pStack[sp-1] : NULL;
411 PopDoubleRef(nCol1, nRow1, nTab1, nCol2, nRow2, nTab2);
412 pMat = CreateMatrixFromDoubleRef( p, nCol1, nRow1, nTab1,
413 nCol2, nRow2, nTab2);
415 break;
416 case svMatrix:
417 pMat = PopMatrix();
418 break;
419 case svError :
420 case svMissing :
421 case svDouble :
423 double fVal = GetDouble();
424 pMat = GetNewMat( 1, 1);
425 if ( pMat )
427 if ( nGlobalError )
429 fVal = CreateDoubleError( nGlobalError);
430 nGlobalError = 0;
432 pMat->PutDouble( fVal, 0);
435 break;
436 case svString :
438 svl::SharedString aStr = GetString();
439 pMat = GetNewMat( 1, 1);
440 if ( pMat )
442 if ( nGlobalError )
444 double fVal = CreateDoubleError( nGlobalError);
445 pMat->PutDouble( fVal, 0);
446 nGlobalError = 0;
448 else
449 pMat->PutString(aStr, 0);
452 break;
453 case svExternalSingleRef:
455 ScExternalRefCache::TokenRef pToken;
456 PopExternalSingleRef(pToken);
457 if (!pToken)
459 PopError();
460 SetError( errIllegalArgument);
461 break;
463 if (pToken->GetType() == svDouble)
465 pMat = new ScMatrix(1, 1, 0.0);
466 pMat->PutDouble(pToken->GetDouble(), 0, 0);
468 else if (pToken->GetType() == svString)
470 pMat = new ScMatrix(1, 1, 0.0);
471 pMat->PutString(pToken->GetString(), 0, 0);
473 else
475 pMat = new ScMatrix(1, 1);
478 break;
479 case svExternalDoubleRef:
480 PopExternalDoubleRef(pMat);
481 break;
482 default:
483 PopError();
484 SetError( errIllegalArgument);
485 break;
487 return pMat;
490 sc::RangeMatrix ScInterpreter::GetRangeMatrix()
492 sc::RangeMatrix aRet;
493 switch (GetRawStackType())
495 case svMatrix:
496 aRet = PopRangeMatrix();
497 break;
498 default:
499 aRet.mpMat = GetMatrix();
501 return aRet;
504 void ScInterpreter::ScMatValue()
506 if ( MustHaveParamCount( GetByte(), 3 ) )
508 // 0 to count-1
509 SCSIZE nR = static_cast<SCSIZE>(::rtl::math::approxFloor(GetDouble()));
510 SCSIZE nC = static_cast<SCSIZE>(::rtl::math::approxFloor(GetDouble()));
511 switch (GetStackType())
513 case svSingleRef :
515 ScAddress aAdr;
516 PopSingleRef( aAdr );
517 ScRefCellValue aCell;
518 aCell.assign(*pDok, aAdr);
519 if (aCell.meType == CELLTYPE_FORMULA)
521 sal_uInt16 nErrCode = aCell.mpFormula->GetErrCode();
522 if (nErrCode != 0)
523 PushError( nErrCode);
524 else
526 const ScMatrix* pMat = aCell.mpFormula->GetMatrix();
527 CalculateMatrixValue(pMat,nC,nR);
530 else
531 PushIllegalParameter();
533 break;
534 case svDoubleRef :
536 SCCOL nCol1;
537 SCROW nRow1;
538 SCTAB nTab1;
539 SCCOL nCol2;
540 SCROW nRow2;
541 SCTAB nTab2;
542 PopDoubleRef(nCol1, nRow1, nTab1, nCol2, nRow2, nTab2);
543 if (nCol2 - nCol1 >= static_cast<SCCOL>(nR) &&
544 nRow2 - nRow1 >= static_cast<SCROW>(nC) &&
545 nTab1 == nTab2)
547 ScAddress aAdr( sal::static_int_cast<SCCOL>( nCol1 + nR ),
548 sal::static_int_cast<SCROW>( nRow1 + nC ), nTab1 );
549 ScRefCellValue aCell;
550 aCell.assign(*pDok, aAdr);
551 if (aCell.hasNumeric())
552 PushDouble(GetCellValue(aAdr, aCell));
553 else
555 svl::SharedString aStr;
556 GetCellString(aStr, aCell);
557 PushString(aStr);
560 else
561 PushNoValue();
563 break;
564 case svMatrix:
566 ScMatrixRef pMat = PopMatrix();
567 CalculateMatrixValue(pMat.get(),nC,nR);
569 break;
570 default:
571 PopError();
572 PushIllegalParameter();
573 break;
577 void ScInterpreter::CalculateMatrixValue(const ScMatrix* pMat,SCSIZE nC,SCSIZE nR)
579 if (pMat)
581 SCSIZE nCl, nRw;
582 pMat->GetDimensions(nCl, nRw);
583 if (nC < nCl && nR < nRw)
585 const ScMatrixValue nMatVal = pMat->Get( nC, nR);
586 ScMatValType nMatValType = nMatVal.nType;
587 if (ScMatrix::IsNonValueType( nMatValType))
588 PushString( nMatVal.GetString() );
589 else
590 PushDouble(nMatVal.fVal);
591 // also handles DoubleError
593 else
594 PushNoValue();
596 else
597 PushNoValue();
600 void ScInterpreter::ScEMat()
602 if ( MustHaveParamCount( GetByte(), 1 ) )
604 SCSIZE nDim = static_cast<SCSIZE>(::rtl::math::approxFloor(GetDouble()));
605 if ( nDim * nDim > ScMatrix::GetElementsMax() || nDim == 0)
606 PushIllegalArgument();
607 else
609 ScMatrixRef pRMat = GetNewMat(nDim, nDim);
610 if (pRMat)
612 MEMat(pRMat, nDim);
613 PushMatrix(pRMat);
615 else
616 PushIllegalArgument();
621 void ScInterpreter::MEMat(const ScMatrixRef& mM, SCSIZE n)
623 mM->FillDouble(0.0, 0, 0, n-1, n-1);
624 for (SCSIZE i = 0; i < n; i++)
625 mM->PutDouble(1.0, i, i);
628 /* Matrix LUP decomposition according to the pseudocode of "Introduction to
629 * Algorithms" by Cormen, Leiserson, Rivest, Stein.
631 * Added scaling for numeric stability.
633 * Given an n x n nonsingular matrix A, find a permutation matrix P, a unit
634 * lower-triangular matrix L, and an upper-triangular matrix U such that PA=LU.
635 * Compute L and U "in place" in the matrix A, the original content is
636 * destroyed. Note that the diagonal elements of the U triangular matrix
637 * replace the diagonal elements of the L-unit matrix (that are each ==1). The
638 * permutation matrix P is an array, where P[i]=j means that the i-th row of P
639 * contains a 1 in column j. Additionally keep track of the number of
640 * permutations (row exchanges).
642 * Returns 0 if a singular matrix is encountered, else +1 if an even number of
643 * permutations occurred, or -1 if odd, which is the sign of the determinant.
644 * This may be used to calculate the determinant by multiplying the sign with
645 * the product of the diagonal elements of the LU matrix.
647 static int lcl_LUP_decompose( ScMatrix* mA, const SCSIZE n,
648 ::std::vector< SCSIZE> & P )
650 int nSign = 1;
651 // Find scale of each row.
652 ::std::vector< double> aScale(n);
653 for (SCSIZE i=0; i < n; ++i)
655 double fMax = 0.0;
656 for (SCSIZE j=0; j < n; ++j)
658 double fTmp = fabs( mA->GetDouble( j, i));
659 if (fMax < fTmp)
660 fMax = fTmp;
662 if (fMax == 0.0)
663 return 0; // singular matrix
664 aScale[i] = 1.0 / fMax;
666 // Represent identity permutation, P[i]=i
667 for (SCSIZE i=0; i < n; ++i)
668 P[i] = i;
669 // "Recursion" on the diagonale.
670 SCSIZE l = n - 1;
671 for (SCSIZE k=0; k < l; ++k)
673 // Implicit pivoting. With the scale found for a row, compare values of
674 // a column and pick largest.
675 double fMax = 0.0;
676 double fScale = aScale[k];
677 SCSIZE kp = k;
678 for (SCSIZE i = k; i < n; ++i)
680 double fTmp = fScale * fabs( mA->GetDouble( k, i));
681 if (fMax < fTmp)
683 fMax = fTmp;
684 kp = i;
687 if (fMax == 0.0)
688 return 0; // singular matrix
689 // Swap rows. The pivot element will be at mA[k,kp] (row,col notation)
690 if (k != kp)
692 // permutations
693 SCSIZE nTmp = P[k];
694 P[k] = P[kp];
695 P[kp] = nTmp;
696 nSign = -nSign;
697 // scales
698 double fTmp = aScale[k];
699 aScale[k] = aScale[kp];
700 aScale[kp] = fTmp;
701 // elements
702 for (SCSIZE i=0; i < n; ++i)
704 double fMatTmp = mA->GetDouble( i, k);
705 mA->PutDouble( mA->GetDouble( i, kp), i, k);
706 mA->PutDouble( fMatTmp, i, kp);
709 // Compute Schur complement.
710 for (SCSIZE i = k+1; i < n; ++i)
712 double fNum = mA->GetDouble( k, i);
713 double fDen = mA->GetDouble( k, k);
714 mA->PutDouble( fNum/fDen, k, i);
715 for (SCSIZE j = k+1; j < n; ++j)
716 mA->PutDouble( ( mA->GetDouble( j, i) * fDen -
717 fNum * mA->GetDouble( j, k) ) / fDen, j, i);
720 #if OSL_DEBUG_LEVEL > 1
721 fprintf( stderr, "\n%s\n", "lcl_LUP_decompose(): LU");
722 for (SCSIZE i=0; i < n; ++i)
724 for (SCSIZE j=0; j < n; ++j)
725 fprintf( stderr, "%8.2g ", mA->GetDouble( j, i));
726 fprintf( stderr, "\n%s\n", "");
728 fprintf( stderr, "\n%s\n", "lcl_LUP_decompose(): P");
729 for (SCSIZE j=0; j < n; ++j)
730 fprintf( stderr, "%5u ", (unsigned)P[j]);
731 fprintf( stderr, "\n%s\n", "");
732 #endif
734 bool bSingular=false;
735 for (SCSIZE i=0; i<n && !bSingular; i++)
736 bSingular = bSingular || ((mA->GetDouble(i,i))==0.0);
737 if (bSingular)
738 nSign = 0;
740 return nSign;
743 /* Solve a LUP decomposed equation Ax=b. LU is a combined matrix of L and U
744 * triangulars and P the permutation vector as obtained from
745 * lcl_LUP_decompose(). B is the right-hand side input vector, X is used to
746 * return the solution vector.
748 static void lcl_LUP_solve( const ScMatrix* mLU, const SCSIZE n,
749 const ::std::vector< SCSIZE> & P, const ::std::vector< double> & B,
750 ::std::vector< double> & X )
752 SCSIZE nFirst = SCSIZE_MAX;
753 // Ax=b => PAx=Pb, with decomposition LUx=Pb.
754 // Define y=Ux and solve for y in Ly=Pb using forward substitution.
755 for (SCSIZE i=0; i < n; ++i)
757 double fSum = B[P[i]];
758 // Matrix inversion comes with a lot of zeros in the B vectors, we
759 // don't have to do all the computing with results multiplied by zero.
760 // Until then, simply lookout for the position of the first nonzero
761 // value.
762 if (nFirst != SCSIZE_MAX)
764 for (SCSIZE j = nFirst; j < i; ++j)
765 fSum -= mLU->GetDouble( j, i) * X[j]; // X[j] === y[j]
767 else if (fSum)
768 nFirst = i;
769 X[i] = fSum; // X[i] === y[i]
771 // Solve for x in Ux=y using back substitution.
772 for (SCSIZE i = n; i--; )
774 double fSum = X[i]; // X[i] === y[i]
775 for (SCSIZE j = i+1; j < n; ++j)
776 fSum -= mLU->GetDouble( j, i) * X[j]; // X[j] === x[j]
777 X[i] = fSum / mLU->GetDouble( i, i); // X[i] === x[i]
779 #if OSL_DEBUG_LEVEL >1
780 fprintf( stderr, "\n%s\n", "lcl_LUP_solve():");
781 for (SCSIZE i=0; i < n; ++i)
782 fprintf( stderr, "%8.2g ", X[i]);
783 fprintf( stderr, "%s\n", "");
784 #endif
787 void ScInterpreter::ScMatDet()
789 if ( MustHaveParamCount( GetByte(), 1 ) )
791 ScMatrixRef pMat = GetMatrix();
792 if (!pMat)
794 PushIllegalParameter();
795 return;
797 if ( !pMat->IsNumeric() )
799 PushNoValue();
800 return;
802 SCSIZE nC, nR;
803 pMat->GetDimensions(nC, nR);
804 if ( nC != nR || nC == 0 || (sal_uLong) nC * nC > ScMatrix::GetElementsMax() )
805 PushIllegalArgument();
806 else
808 // LUP decomposition is done inplace, use copy.
809 ScMatrixRef xLU = pMat->Clone();
810 if (!xLU)
811 PushError( errCodeOverflow);
812 else
814 ::std::vector< SCSIZE> P(nR);
815 int nDetSign = lcl_LUP_decompose( xLU.get(), nR, P);
816 if (!nDetSign)
817 PushInt(0); // singular matrix
818 else
820 // In an LU matrix the determinant is simply the product of
821 // all diagonal elements.
822 double fDet = nDetSign;
823 for (SCSIZE i=0; i < nR; ++i)
824 fDet *= xLU->GetDouble( i, i);
825 PushDouble( fDet);
832 void ScInterpreter::ScModalValue_Multi()
834 sal_uInt8 nParamCount = GetByte();
835 if ( !MustHaveParamCountMin( nParamCount, 1 ) )
836 return;
837 vector<double> aSortArray;
838 GetSortArray( nParamCount, aSortArray, NULL, false, false );
839 SCSIZE nSize = aSortArray.size();
840 if ( aSortArray.empty() || nSize == 0 || nGlobalError )
841 PushNoValue();
842 else
844 SCSIZE nMax = 1, nCount = 1;
845 double nOldVal = aSortArray[0];
846 vector<double> aResultArray;
847 aResultArray.resize( 1 );
848 aResultArray[ 0 ] = aSortArray[ 0 ];
849 SCSIZE i;
851 for ( i = 1; i < nSize; i++ )
853 if ( aSortArray[ i ] == nOldVal )
855 nCount++;
856 if ( nCount > nMax && aResultArray.size() > 1 )
858 aResultArray.clear();
859 aResultArray.resize( 1 );
860 aResultArray[ 0 ] = nOldVal;
863 else
865 nOldVal = aSortArray[ i ];
866 if ( nCount >= nMax )
868 if ( nCount > nMax )
869 nMax = nCount;
870 aResultArray.resize( aResultArray.size() + 1 );
872 aResultArray[ aResultArray.size() -1 ] = nOldVal;
873 nCount = 1;
876 if ( nCount > nMax )
877 nMax = nCount;
878 else
880 if ( nCount < nMax )
881 aResultArray.resize( aResultArray.size() - 1 );
884 if ( nMax == 1 && nCount == 1 )
885 PushNoValue();
886 else
888 ScMatrixRef pResMatrix = GetNewMat( 1, aResultArray.size(), true );
889 pResMatrix->PutDoubleVector( aResultArray, 0, 0 );
890 PushMatrix( pResMatrix );
895 void ScInterpreter::ScMatInv()
897 if ( MustHaveParamCount( GetByte(), 1 ) )
899 ScMatrixRef pMat = GetMatrix();
900 if (!pMat)
902 PushIllegalParameter();
903 return;
905 if ( !pMat->IsNumeric() )
907 PushNoValue();
908 return;
910 SCSIZE nC, nR;
911 pMat->GetDimensions(nC, nR);
913 if (officecfg::Office::Common::Misc::UseOpenCL::get())
915 sc::FormulaGroupInterpreter *pInterpreter = sc::FormulaGroupInterpreter::getStatic();
916 if (pInterpreter != NULL)
918 ScMatrixRef xResMat = pInterpreter->inverseMatrix(*pMat);
919 if (xResMat)
921 PushMatrix(xResMat);
922 return;
927 if ( nC != nR || nC == 0 || (sal_uLong) nC * nC > ScMatrix::GetElementsMax() )
928 PushIllegalArgument();
929 else
931 // LUP decomposition is done inplace, use copy.
932 ScMatrixRef xLU = pMat->Clone();
933 // The result matrix.
934 ScMatrixRef xY = GetNewMat( nR, nR);
935 if (!xLU || !xY)
936 PushError( errCodeOverflow);
937 else
939 ::std::vector< SCSIZE> P(nR);
940 int nDetSign = lcl_LUP_decompose( xLU.get(), nR, P);
941 if (!nDetSign)
942 PushIllegalArgument();
943 else
945 // Solve equation for each column.
946 ::std::vector< double> B(nR);
947 ::std::vector< double> X(nR);
948 for (SCSIZE j=0; j < nR; ++j)
950 for (SCSIZE i=0; i < nR; ++i)
951 B[i] = 0.0;
952 B[j] = 1.0;
953 lcl_LUP_solve( xLU.get(), nR, P, B, X);
954 for (SCSIZE i=0; i < nR; ++i)
955 xY->PutDouble( X[i], j, i);
957 #if OSL_DEBUG_LEVEL > 1
958 /* Possible checks for ill-condition:
959 * 1. Scale matrix, invert scaled matrix. If there are
960 * elements of the inverted matrix that are several
961 * orders of magnitude greater than 1 =>
962 * ill-conditioned.
963 * Just how much is "several orders"?
964 * 2. Invert the inverted matrix and assess whether the
965 * result is sufficiently close to the original matrix.
966 * If not => ill-conditioned.
967 * Just what is sufficient?
968 * 3. Multiplying the inverse by the original matrix should
969 * produce a result sufficiently close to the identity
970 * matrix.
971 * Just what is sufficient?
973 * The following is #3.
975 const double fInvEpsilon = 1.0E-7;
976 ScMatrixRef xR = GetNewMat( nR, nR);
977 if (xR)
979 ScMatrix* pR = xR.get();
980 lcl_MFastMult( pMat, xY.get(), pR, nR, nR, nR);
981 fprintf( stderr, "\n%s\n", "ScMatInv(): mult-identity");
982 for (SCSIZE i=0; i < nR; ++i)
984 for (SCSIZE j=0; j < nR; ++j)
986 double fTmp = pR->GetDouble( j, i);
987 fprintf( stderr, "%8.2g ", fTmp);
988 if (fabs( fTmp - (i == j)) > fInvEpsilon)
989 SetError( errIllegalArgument);
991 fprintf( stderr, "\n%s\n", "");
994 #endif
995 if (nGlobalError)
996 PushError( nGlobalError);
997 else
998 PushMatrix( xY);
1005 void ScInterpreter::ScMatMult()
1007 if ( MustHaveParamCount( GetByte(), 2 ) )
1009 ScMatrixRef pMat2 = GetMatrix();
1010 ScMatrixRef pMat1 = GetMatrix();
1011 ScMatrixRef pRMat;
1012 if (pMat1 && pMat2)
1014 if ( pMat1->IsNumeric() && pMat2->IsNumeric() )
1016 SCSIZE nC1, nC2;
1017 SCSIZE nR1, nR2;
1018 pMat1->GetDimensions(nC1, nR1);
1019 pMat2->GetDimensions(nC2, nR2);
1020 if (nC1 != nR2)
1021 PushIllegalArgument();
1022 else
1024 pRMat = GetNewMat(nC2, nR1);
1025 if (pRMat)
1027 double sum;
1028 for (SCSIZE i = 0; i < nR1; i++)
1030 for (SCSIZE j = 0; j < nC2; j++)
1032 sum = 0.0;
1033 for (SCSIZE k = 0; k < nC1; k++)
1035 sum += pMat1->GetDouble(k,i)*pMat2->GetDouble(j,k);
1037 pRMat->PutDouble(sum, j, i);
1040 PushMatrix(pRMat);
1042 else
1043 PushIllegalArgument();
1046 else
1047 PushNoValue();
1049 else
1050 PushIllegalParameter();
1054 void ScInterpreter::ScMatTrans()
1056 if ( MustHaveParamCount( GetByte(), 1 ) )
1058 ScMatrixRef pMat = GetMatrix();
1059 ScMatrixRef pRMat;
1060 if (pMat)
1062 SCSIZE nC, nR;
1063 pMat->GetDimensions(nC, nR);
1064 pRMat = GetNewMat(nR, nC);
1065 if ( pRMat )
1067 pMat->MatTrans(*pRMat);
1068 PushMatrix(pRMat);
1070 else
1071 PushIllegalArgument();
1073 else
1074 PushIllegalParameter();
1078 /** Minimum extent of one result matrix dimension.
1079 For a row or column vector to be replicated the larger matrix dimension is
1080 returned, else the smaller dimension.
1082 static inline SCSIZE lcl_GetMinExtent( SCSIZE n1, SCSIZE n2 )
1084 if (n1 == 1)
1085 return n2;
1086 else if (n2 == 1)
1087 return n1;
1088 else if (n1 < n2)
1089 return n1;
1090 else
1091 return n2;
1094 template<class _Function>
1095 static ScMatrixRef lcl_MatrixCalculation(
1096 const ScMatrix& rMat1, const ScMatrix& rMat2, ScInterpreter* pInterpreter)
1098 static _Function Op;
1100 SCSIZE nC1, nC2, nMinC;
1101 SCSIZE nR1, nR2, nMinR;
1102 SCSIZE i, j;
1103 rMat1.GetDimensions(nC1, nR1);
1104 rMat2.GetDimensions(nC2, nR2);
1105 nMinC = lcl_GetMinExtent( nC1, nC2);
1106 nMinR = lcl_GetMinExtent( nR1, nR2);
1107 ScMatrixRef xResMat = pInterpreter->GetNewMat(nMinC, nMinR);
1108 if (xResMat)
1110 for (i = 0; i < nMinC; i++)
1112 for (j = 0; j < nMinR; j++)
1114 bool bVal1 = rMat1.IsValueOrEmpty(i,j);
1115 bool bVal2 = rMat2.IsValueOrEmpty(i,j);
1116 sal_uInt16 nErr;
1117 if (bVal1 && bVal2)
1119 double d = Op(rMat1.GetDouble(i,j), rMat2.GetDouble(i,j));
1120 xResMat->PutDouble( d, i, j);
1122 else if (((nErr = rMat1.GetErrorIfNotString(i,j)) != 0) ||
1123 ((nErr = rMat2.GetErrorIfNotString(i,j)) != 0))
1125 xResMat->PutError( nErr, i, j);
1127 else if ((!bVal1 && rMat1.IsString(i,j)) || (!bVal2 && rMat2.IsString(i,j)))
1129 sal_uInt16 nError1 = 0;
1130 short nFmt1 = 0;
1131 double fVal1 = (bVal1 ? rMat1.GetDouble(i,j) :
1132 pInterpreter->ConvertStringToValue( rMat1.GetString(i,j).getString(), nError1, nFmt1));
1134 sal_uInt16 nError2 = 0;
1135 short nFmt2 = 0;
1136 double fVal2 = (bVal2 ? rMat2.GetDouble(i,j) :
1137 pInterpreter->ConvertStringToValue( rMat2.GetString(i,j).getString(), nError2, nFmt2));
1139 if (nError1)
1140 xResMat->PutError( nError1, i, j);
1141 else if (nError2)
1142 xResMat->PutError( nError2, i, j);
1143 else
1145 double d = Op( fVal1, fVal2);
1146 xResMat->PutDouble( d, i, j);
1149 else
1150 xResMat->PutError( errNoValue, i, j);
1154 return xResMat;
1157 ScMatrixRef ScInterpreter::MatConcat(const ScMatrixRef& pMat1, const ScMatrixRef& pMat2)
1159 SCSIZE nC1, nC2, nMinC;
1160 SCSIZE nR1, nR2, nMinR;
1161 SCSIZE i, j;
1162 pMat1->GetDimensions(nC1, nR1);
1163 pMat2->GetDimensions(nC2, nR2);
1164 nMinC = lcl_GetMinExtent( nC1, nC2);
1165 nMinR = lcl_GetMinExtent( nR1, nR2);
1166 ScMatrixRef xResMat = GetNewMat(nMinC, nMinR);
1167 if (xResMat)
1169 for (i = 0; i < nMinC; i++)
1171 for (j = 0; j < nMinR; j++)
1173 sal_uInt16 nErr = pMat1->GetErrorIfNotString( i, j);
1174 if (!nErr)
1175 nErr = pMat2->GetErrorIfNotString( i, j);
1176 if (nErr)
1177 xResMat->PutError( nErr, i, j);
1178 else
1180 OUString aTmp = pMat1->GetString(*pFormatter, i, j).getString();
1181 aTmp += pMat2->GetString(*pFormatter, i, j).getString();
1182 xResMat->PutString(mrStrPool.intern(aTmp), i, j);
1187 return xResMat;
1190 // for DATE, TIME, DATETIME
1191 static void lcl_GetDiffDateTimeFmtType( short& nFuncFmt, short nFmt1, short nFmt2 )
1193 if ( nFmt1 != css::util::NumberFormat::UNDEFINED || nFmt2 != css::util::NumberFormat::UNDEFINED )
1195 if ( nFmt1 == nFmt2 )
1197 if ( nFmt1 == css::util::NumberFormat::TIME || nFmt1 == css::util::NumberFormat::DATETIME )
1198 nFuncFmt = css::util::NumberFormat::TIME; // times result in time
1199 // else: nothing special, number (date - date := days)
1201 else if ( nFmt1 == css::util::NumberFormat::UNDEFINED )
1202 nFuncFmt = nFmt2; // e.g. date + days := date
1203 else if ( nFmt2 == css::util::NumberFormat::UNDEFINED )
1204 nFuncFmt = nFmt1;
1205 else
1207 if ( nFmt1 == css::util::NumberFormat::DATE || nFmt2 == css::util::NumberFormat::DATE ||
1208 nFmt1 == css::util::NumberFormat::DATETIME || nFmt2 == css::util::NumberFormat::DATETIME )
1210 if ( nFmt1 == css::util::NumberFormat::TIME || nFmt2 == css::util::NumberFormat::TIME )
1211 nFuncFmt = css::util::NumberFormat::DATETIME; // date + time
1217 void ScInterpreter::ScAdd()
1219 CalculateAddSub(false);
1222 namespace {
1226 void ScInterpreter::CalculateAddSub(bool _bSub)
1228 ScMatrixRef pMat1 = NULL;
1229 ScMatrixRef pMat2 = NULL;
1230 double fVal1 = 0.0, fVal2 = 0.0;
1231 short nFmt1, nFmt2;
1232 nFmt1 = nFmt2 = css::util::NumberFormat::UNDEFINED;
1233 short nFmtCurrencyType = nCurFmtType;
1234 sal_uLong nFmtCurrencyIndex = nCurFmtIndex;
1235 short nFmtPercentType = nCurFmtType;
1236 if ( GetStackType() == svMatrix )
1237 pMat2 = GetMatrix();
1238 else
1240 fVal2 = GetDouble();
1241 switch ( nCurFmtType )
1243 case css::util::NumberFormat::DATE :
1244 case css::util::NumberFormat::TIME :
1245 case css::util::NumberFormat::DATETIME :
1246 nFmt2 = nCurFmtType;
1247 break;
1248 case css::util::NumberFormat::CURRENCY :
1249 nFmtCurrencyType = nCurFmtType;
1250 nFmtCurrencyIndex = nCurFmtIndex;
1251 break;
1252 case css::util::NumberFormat::PERCENT :
1253 nFmtPercentType = css::util::NumberFormat::PERCENT;
1254 break;
1257 if ( GetStackType() == svMatrix )
1258 pMat1 = GetMatrix();
1259 else
1261 fVal1 = GetDouble();
1262 switch ( nCurFmtType )
1264 case css::util::NumberFormat::DATE :
1265 case css::util::NumberFormat::TIME :
1266 case css::util::NumberFormat::DATETIME :
1267 nFmt1 = nCurFmtType;
1268 break;
1269 case css::util::NumberFormat::CURRENCY :
1270 nFmtCurrencyType = nCurFmtType;
1271 nFmtCurrencyIndex = nCurFmtIndex;
1272 break;
1273 case css::util::NumberFormat::PERCENT :
1274 nFmtPercentType = css::util::NumberFormat::PERCENT;
1275 break;
1278 if (pMat1 && pMat2)
1280 ScMatrixRef pResMat;
1281 if ( _bSub )
1283 pResMat = lcl_MatrixCalculation<MatrixSub>( *pMat1, *pMat2, this);
1285 else
1287 pResMat = lcl_MatrixCalculation<MatrixAdd>( *pMat1, *pMat2, this);
1290 if (!pResMat)
1291 PushNoValue();
1292 else
1293 PushMatrix(pResMat);
1295 else if (pMat1 || pMat2)
1297 double fVal;
1298 bool bFlag;
1299 ScMatrixRef pMat = pMat1;
1300 if (!pMat)
1302 fVal = fVal1;
1303 pMat = pMat2;
1304 bFlag = true; // double - Matrix
1306 else
1308 fVal = fVal2;
1309 bFlag = false; // Matrix - double
1311 SCSIZE nC, nR;
1312 pMat->GetDimensions(nC, nR);
1313 ScMatrixRef pResMat = GetNewMat(nC, nR, true);
1314 if (pResMat)
1316 if (_bSub)
1318 pMat->SubOp( bFlag, fVal, *pResMat);
1320 else
1322 pMat->AddOp( fVal, *pResMat);
1324 PushMatrix(pResMat);
1326 else
1327 PushIllegalArgument();
1329 else if ( _bSub )
1330 PushDouble( ::rtl::math::approxSub( fVal1, fVal2 ) );
1331 else
1332 PushDouble( ::rtl::math::approxAdd( fVal1, fVal2 ) );
1333 if ( nFmtCurrencyType == css::util::NumberFormat::CURRENCY )
1335 nFuncFmtType = nFmtCurrencyType;
1336 nFuncFmtIndex = nFmtCurrencyIndex;
1338 else
1340 lcl_GetDiffDateTimeFmtType( nFuncFmtType, nFmt1, nFmt2 );
1341 if ( nFmtPercentType == css::util::NumberFormat::PERCENT && nFuncFmtType == css::util::NumberFormat::NUMBER )
1342 nFuncFmtType = css::util::NumberFormat::PERCENT;
1346 void ScInterpreter::ScAmpersand()
1348 ScMatrixRef pMat1 = NULL;
1349 ScMatrixRef pMat2 = NULL;
1350 OUString sStr1, sStr2;
1351 if ( GetStackType() == svMatrix )
1352 pMat2 = GetMatrix();
1353 else
1354 sStr2 = GetString().getString();
1355 if ( GetStackType() == svMatrix )
1356 pMat1 = GetMatrix();
1357 else
1358 sStr1 = GetString().getString();
1359 if (pMat1 && pMat2)
1361 ScMatrixRef pResMat = MatConcat(pMat1, pMat2);
1362 if (!pResMat)
1363 PushNoValue();
1364 else
1365 PushMatrix(pResMat);
1367 else if (pMat1 || pMat2)
1369 OUString sStr;
1370 bool bFlag;
1371 ScMatrixRef pMat = pMat1;
1372 if (!pMat)
1374 sStr = sStr1;
1375 pMat = pMat2;
1376 bFlag = true; // double - Matrix
1378 else
1380 sStr = sStr2;
1381 bFlag = false; // Matrix - double
1383 SCSIZE nC, nR;
1384 pMat->GetDimensions(nC, nR);
1385 ScMatrixRef pResMat = GetNewMat(nC, nR);
1386 if (pResMat)
1388 if (nGlobalError)
1390 for (SCSIZE i = 0; i < nC; ++i)
1391 for (SCSIZE j = 0; j < nR; ++j)
1392 pResMat->PutError( nGlobalError, i, j);
1394 else if (bFlag)
1396 for (SCSIZE i = 0; i < nC; ++i)
1397 for (SCSIZE j = 0; j < nR; ++j)
1399 sal_uInt16 nErr = pMat->GetErrorIfNotString( i, j);
1400 if (nErr)
1401 pResMat->PutError( nErr, i, j);
1402 else
1404 OUString aTmp = sStr;
1405 aTmp += pMat->GetString(*pFormatter, i, j).getString();
1406 pResMat->PutString(mrStrPool.intern(aTmp), i, j);
1410 else
1412 for (SCSIZE i = 0; i < nC; ++i)
1413 for (SCSIZE j = 0; j < nR; ++j)
1415 sal_uInt16 nErr = pMat->GetErrorIfNotString( i, j);
1416 if (nErr)
1417 pResMat->PutError( nErr, i, j);
1418 else
1420 OUString aTmp = pMat->GetString(*pFormatter, i, j).getString();
1421 aTmp += sStr;
1422 pResMat->PutString(mrStrPool.intern(aTmp), i, j);
1426 PushMatrix(pResMat);
1428 else
1429 PushIllegalArgument();
1431 else
1433 if ( CheckStringResultLen( sStr1, sStr2 ) )
1434 sStr1 += sStr2;
1435 PushString(sStr1);
1439 void ScInterpreter::ScSub()
1441 CalculateAddSub(true);
1444 void ScInterpreter::ScMul()
1446 ScMatrixRef pMat1 = NULL;
1447 ScMatrixRef pMat2 = NULL;
1448 double fVal1 = 0.0, fVal2 = 0.0;
1449 short nFmtCurrencyType = nCurFmtType;
1450 sal_uLong nFmtCurrencyIndex = nCurFmtIndex;
1451 if ( GetStackType() == svMatrix )
1452 pMat2 = GetMatrix();
1453 else
1455 fVal2 = GetDouble();
1456 switch ( nCurFmtType )
1458 case css::util::NumberFormat::CURRENCY :
1459 nFmtCurrencyType = nCurFmtType;
1460 nFmtCurrencyIndex = nCurFmtIndex;
1461 break;
1464 if ( GetStackType() == svMatrix )
1465 pMat1 = GetMatrix();
1466 else
1468 fVal1 = GetDouble();
1469 switch ( nCurFmtType )
1471 case css::util::NumberFormat::CURRENCY :
1472 nFmtCurrencyType = nCurFmtType;
1473 nFmtCurrencyIndex = nCurFmtIndex;
1474 break;
1477 if (pMat1 && pMat2)
1479 ScMatrixRef pResMat = lcl_MatrixCalculation<MatrixMul>( *pMat1, *pMat2, this);
1480 if (!pResMat)
1481 PushNoValue();
1482 else
1483 PushMatrix(pResMat);
1485 else if (pMat1 || pMat2)
1487 double fVal;
1488 ScMatrixRef pMat = pMat1;
1489 if (!pMat)
1491 fVal = fVal1;
1492 pMat = pMat2;
1494 else
1495 fVal = fVal2;
1496 SCSIZE nC, nR;
1497 pMat->GetDimensions(nC, nR);
1498 ScMatrixRef pResMat = GetNewMat(nC, nR);
1499 if (pResMat)
1501 pMat->MulOp( fVal, *pResMat);
1502 PushMatrix(pResMat);
1504 else
1505 PushIllegalArgument();
1507 else
1508 PushDouble(fVal1 * fVal2);
1509 if ( nFmtCurrencyType == css::util::NumberFormat::CURRENCY )
1511 nFuncFmtType = nFmtCurrencyType;
1512 nFuncFmtIndex = nFmtCurrencyIndex;
1516 void ScInterpreter::ScDiv()
1518 ScMatrixRef pMat1 = NULL;
1519 ScMatrixRef pMat2 = NULL;
1520 double fVal1 = 0.0, fVal2 = 0.0;
1521 short nFmtCurrencyType = nCurFmtType;
1522 sal_uLong nFmtCurrencyIndex = nCurFmtIndex;
1523 short nFmtCurrencyType2 = css::util::NumberFormat::UNDEFINED;
1524 if ( GetStackType() == svMatrix )
1525 pMat2 = GetMatrix();
1526 else
1528 fVal2 = GetDouble();
1529 // do not take over currency, 123kg/456USD is not USD
1530 nFmtCurrencyType2 = nCurFmtType;
1532 if ( GetStackType() == svMatrix )
1533 pMat1 = GetMatrix();
1534 else
1536 fVal1 = GetDouble();
1537 switch ( nCurFmtType )
1539 case css::util::NumberFormat::CURRENCY :
1540 nFmtCurrencyType = nCurFmtType;
1541 nFmtCurrencyIndex = nCurFmtIndex;
1542 break;
1545 if (pMat1 && pMat2)
1547 ScMatrixRef pResMat = lcl_MatrixCalculation<MatrixDiv>( *pMat1, *pMat2, this);
1548 if (!pResMat)
1549 PushNoValue();
1550 else
1551 PushMatrix(pResMat);
1553 else if (pMat1 || pMat2)
1555 double fVal;
1556 bool bFlag;
1557 ScMatrixRef pMat = pMat1;
1558 if (!pMat)
1560 fVal = fVal1;
1561 pMat = pMat2;
1562 bFlag = true; // double - Matrix
1564 else
1566 fVal = fVal2;
1567 bFlag = false; // Matrix - double
1569 SCSIZE nC, nR;
1570 pMat->GetDimensions(nC, nR);
1571 ScMatrixRef pResMat = GetNewMat(nC, nR);
1572 if (pResMat)
1574 pMat->DivOp( bFlag, fVal, *pResMat);
1575 PushMatrix(pResMat);
1577 else
1578 PushIllegalArgument();
1580 else
1582 PushDouble( div( fVal1, fVal2) );
1584 if ( nFmtCurrencyType == css::util::NumberFormat::CURRENCY && nFmtCurrencyType2 != css::util::NumberFormat::CURRENCY )
1585 { // even USD/USD is not USD
1586 nFuncFmtType = nFmtCurrencyType;
1587 nFuncFmtIndex = nFmtCurrencyIndex;
1591 void ScInterpreter::ScPower()
1593 if ( MustHaveParamCount( GetByte(), 2 ) )
1594 ScPow();
1597 void ScInterpreter::ScPow()
1599 ScMatrixRef pMat1 = NULL;
1600 ScMatrixRef pMat2 = NULL;
1601 double fVal1 = 0.0, fVal2 = 0.0;
1602 if ( GetStackType() == svMatrix )
1603 pMat2 = GetMatrix();
1604 else
1605 fVal2 = GetDouble();
1606 if ( GetStackType() == svMatrix )
1607 pMat1 = GetMatrix();
1608 else
1609 fVal1 = GetDouble();
1610 if (pMat1 && pMat2)
1612 ScMatrixRef pResMat = lcl_MatrixCalculation<MatrixPow>( *pMat1, *pMat2, this);
1613 if (!pResMat)
1614 PushNoValue();
1615 else
1616 PushMatrix(pResMat);
1618 else if (pMat1 || pMat2)
1620 double fVal;
1621 bool bFlag;
1622 ScMatrixRef pMat = pMat1;
1623 if (!pMat)
1625 fVal = fVal1;
1626 pMat = pMat2;
1627 bFlag = true; // double - Matrix
1629 else
1631 fVal = fVal2;
1632 bFlag = false; // Matrix - double
1634 SCSIZE nC, nR;
1635 pMat->GetDimensions(nC, nR);
1636 ScMatrixRef pResMat = GetNewMat(nC, nR);
1637 if (pResMat)
1639 pMat->PowOp( bFlag, fVal, *pResMat);
1640 PushMatrix(pResMat);
1642 else
1643 PushIllegalArgument();
1645 else
1647 if (fVal1 < 0 && fVal2 != 0.0)
1649 int i = (int) (1 / fVal2 + ((fVal2 < 0) ? -0.5 : 0.5));
1650 if (rtl::math::approxEqual(1 / ((double) i), fVal2) && i % 2 != 0)
1651 PushDouble(-pow(-fVal1, fVal2));
1652 else
1653 PushDouble(pow(fVal1, fVal2));
1655 else
1657 PushDouble(pow(fVal1,fVal2));
1662 namespace {
1664 class SumValues : std::unary_function<double, void>
1666 double mfSum;
1667 bool mbError;
1668 public:
1669 SumValues() : mfSum(0.0), mbError(false) {}
1671 void operator() (double f)
1673 if (mbError)
1674 return;
1676 sal_uInt16 nErr = GetDoubleErrorValue(f);
1677 if (!nErr)
1678 mfSum += f;
1679 else if (nErr != errElementNaN)
1681 // Propagate the first error encountered, ignore "this is not a
1682 // number" elements.
1683 mfSum = f;
1684 mbError = true;
1688 double getValue() const { return mfSum; }
1693 void ScInterpreter::ScSumProduct()
1695 sal_uInt8 nParamCount = GetByte();
1696 if ( !MustHaveParamCount( nParamCount, 1, 30 ) )
1697 return;
1699 ScMatrixRef pMatLast;
1700 ScMatrixRef pMat;
1702 pMatLast = GetMatrix();
1703 if (!pMatLast)
1705 PushIllegalParameter();
1706 return;
1709 SCSIZE nC, nCLast, nR, nRLast;
1710 pMatLast->GetDimensions(nCLast, nRLast);
1711 std::vector<double> aResArray;
1712 pMatLast->GetDoubleArray(aResArray);
1714 for (sal_uInt16 i = 1; i < nParamCount; ++i)
1716 pMat = GetMatrix();
1717 if (!pMat)
1719 PushIllegalParameter();
1720 return;
1722 pMat->GetDimensions(nC, nR);
1723 if (nC != nCLast || nR != nRLast)
1725 PushNoValue();
1726 return;
1729 pMat->MergeDoubleArray(aResArray, ScMatrix::Mul);
1732 double fSum = std::for_each(aResArray.begin(), aResArray.end(), SumValues()).getValue();
1733 PushDouble(fSum);
1736 void ScInterpreter::ScSumX2MY2()
1738 CalculateSumX2MY2SumX2DY2(false);
1740 void ScInterpreter::CalculateSumX2MY2SumX2DY2(bool _bSumX2DY2)
1742 if ( !MustHaveParamCount( GetByte(), 2 ) )
1743 return;
1745 ScMatrixRef pMat1 = NULL;
1746 ScMatrixRef pMat2 = NULL;
1747 SCSIZE i, j;
1748 pMat2 = GetMatrix();
1749 pMat1 = GetMatrix();
1750 if (!pMat2 || !pMat1)
1752 PushIllegalParameter();
1753 return;
1755 SCSIZE nC1, nC2;
1756 SCSIZE nR1, nR2;
1757 pMat2->GetDimensions(nC2, nR2);
1758 pMat1->GetDimensions(nC1, nR1);
1759 if (nC1 != nC2 || nR1 != nR2)
1761 PushNoValue();
1762 return;
1764 double fVal, fSum = 0.0;
1765 for (i = 0; i < nC1; i++)
1766 for (j = 0; j < nR1; j++)
1767 if (!pMat1->IsString(i,j) && !pMat2->IsString(i,j))
1769 fVal = pMat1->GetDouble(i,j);
1770 fSum += fVal * fVal;
1771 fVal = pMat2->GetDouble(i,j);
1772 if ( _bSumX2DY2 )
1773 fSum += fVal * fVal;
1774 else
1775 fSum -= fVal * fVal;
1777 PushDouble(fSum);
1780 void ScInterpreter::ScSumX2DY2()
1782 CalculateSumX2MY2SumX2DY2(true);
1785 void ScInterpreter::ScSumXMY2()
1787 if ( !MustHaveParamCount( GetByte(), 2 ) )
1788 return;
1790 ScMatrixRef pMat1 = NULL;
1791 ScMatrixRef pMat2 = NULL;
1792 pMat2 = GetMatrix();
1793 pMat1 = GetMatrix();
1794 if (!pMat2 || !pMat1)
1796 PushIllegalParameter();
1797 return;
1799 SCSIZE nC1, nC2;
1800 SCSIZE nR1, nR2;
1801 pMat2->GetDimensions(nC2, nR2);
1802 pMat1->GetDimensions(nC1, nR1);
1803 if (nC1 != nC2 || nR1 != nR2)
1805 PushNoValue();
1806 return;
1807 } // if (nC1 != nC2 || nR1 != nR2)
1808 ScMatrixRef pResMat = lcl_MatrixCalculation<MatrixSub>( *pMat1, *pMat2, this);
1809 if (!pResMat)
1811 PushNoValue();
1813 else
1815 ScMatrix::IterateResult aRes = pResMat->SumSquare(false);
1816 double fSum = aRes.mfFirst + aRes.mfRest;
1817 PushDouble(fSum);
1821 void ScInterpreter::ScFrequency()
1823 if ( !MustHaveParamCount( GetByte(), 2 ) )
1824 return;
1826 vector<double> aBinArray;
1827 vector<long> aBinIndexOrder;
1829 GetSortArray( 1, aBinArray, &aBinIndexOrder, false, false );
1830 SCSIZE nBinSize = aBinArray.size();
1831 if (nGlobalError)
1833 PushNoValue();
1834 return;
1837 vector<double> aDataArray;
1838 GetSortArray( 1, aDataArray, NULL, false, false );
1839 SCSIZE nDataSize = aDataArray.size();
1841 if (aDataArray.empty() || nGlobalError)
1843 PushNoValue();
1844 return;
1846 ScMatrixRef pResMat = GetNewMat(1, nBinSize+1);
1847 if (!pResMat)
1849 PushIllegalArgument();
1850 return;
1853 if (nBinSize != aBinIndexOrder.size())
1855 PushIllegalArgument();
1856 return;
1859 SCSIZE j;
1860 SCSIZE i = 0;
1861 for (j = 0; j < nBinSize; ++j)
1863 SCSIZE nCount = 0;
1864 while (i < nDataSize && aDataArray[i] <= aBinArray[j])
1866 ++nCount;
1867 ++i;
1869 pResMat->PutDouble(static_cast<double>(nCount), aBinIndexOrder[j]);
1871 pResMat->PutDouble(static_cast<double>(nDataSize-i), j);
1872 PushMatrix(pResMat);
1875 namespace {
1877 // Helper methods for LINEST/LOGEST and TREND/GROWTH
1878 // All matrices must already exist and have the needed size, no control tests
1879 // done. Those methods, which names start with lcl_T, are adapted to case 3,
1880 // where Y (=observed values) is given as row.
1881 // Remember, ScMatrix matrices are zero based, index access (column,row).
1883 // <A;B> over all elements; uses the matrices as vectors of length M
1884 double lcl_GetSumProduct(ScMatrixRef pMatA, ScMatrixRef pMatB, SCSIZE nM)
1886 double fSum = 0.0;
1887 for (SCSIZE i=0; i<nM; i++)
1888 fSum += pMatA->GetDouble(i) * pMatB->GetDouble(i);
1889 return fSum;
1892 // Special version for use within QR decomposition.
1893 // Euclidean norm of column index C starting in row index R;
1894 // matrix A has count N rows.
1895 double lcl_GetColumnEuclideanNorm(ScMatrixRef pMatA, SCSIZE nC, SCSIZE nR, SCSIZE nN)
1897 double fNorm = 0.0;
1898 for (SCSIZE row=nR; row<nN; row++)
1899 fNorm += (pMatA->GetDouble(nC,row)) * (pMatA->GetDouble(nC,row));
1900 return sqrt(fNorm);
1903 // Euclidean norm of row index R starting in column index C;
1904 // matrix A has count N columns.
1905 double lcl_TGetColumnEuclideanNorm(ScMatrixRef pMatA, SCSIZE nR, SCSIZE nC, SCSIZE nN)
1907 double fNorm = 0.0;
1908 for (SCSIZE col=nC; col<nN; col++)
1909 fNorm += (pMatA->GetDouble(col,nR)) * (pMatA->GetDouble(col,nR));
1910 return sqrt(fNorm);
1913 // Special version for use within QR decomposition.
1914 // Maximum norm of column index C starting in row index R;
1915 // matrix A has count N rows.
1916 double lcl_GetColumnMaximumNorm(ScMatrixRef pMatA, SCSIZE nC, SCSIZE nR, SCSIZE nN)
1918 double fNorm = 0.0;
1919 for (SCSIZE row=nR; row<nN; row++)
1920 if (fNorm < fabs(pMatA->GetDouble(nC,row)))
1921 fNorm = fabs(pMatA->GetDouble(nC,row));
1922 return fNorm;
1925 // Maximum norm of row index R starting in col index C;
1926 // matrix A has count N columns.
1927 double lcl_TGetColumnMaximumNorm(ScMatrixRef pMatA, SCSIZE nR, SCSIZE nC, SCSIZE nN)
1929 double fNorm = 0.0;
1930 for (SCSIZE col=nC; col<nN; col++)
1931 if (fNorm < fabs(pMatA->GetDouble(col,nR)))
1932 fNorm = fabs(pMatA->GetDouble(col,nR));
1933 return fNorm;
1936 // Special version for use within QR decomposition.
1937 // <A(Ca);B(Cb)> starting in row index R;
1938 // Ca and Cb are indices of columns, matrices A and B have count N rows.
1939 double lcl_GetColumnSumProduct(ScMatrixRef pMatA, SCSIZE nCa,
1940 ScMatrixRef pMatB, SCSIZE nCb, SCSIZE nR, SCSIZE nN)
1942 double fResult = 0.0;
1943 for (SCSIZE row=nR; row<nN; row++)
1944 fResult += pMatA->GetDouble(nCa,row) * pMatB->GetDouble(nCb,row);
1945 return fResult;
1948 // <A(Ra);B(Rb)> starting in column index C;
1949 // Ra and Rb are indices of rows, matrices A and B have count N columns.
1950 double lcl_TGetColumnSumProduct(ScMatrixRef pMatA, SCSIZE nRa,
1951 ScMatrixRef pMatB, SCSIZE nRb, SCSIZE nC, SCSIZE nN)
1953 double fResult = 0.0;
1954 for (SCSIZE col=nC; col<nN; col++)
1955 fResult += pMatA->GetDouble(col,nRa) * pMatB->GetDouble(col,nRb);
1956 return fResult;
1959 // no mathematical signum, but used to switch between adding and subtracting
1960 double lcl_GetSign(double fValue)
1962 return (fValue >= 0.0 ? 1.0 : -1.0 );
1965 /* Calculates a QR decomposition with Householder reflection.
1966 * For each NxK matrix A exists a decomposition A=Q*R with an orthogonal
1967 * NxN matrix Q and a NxK matrix R.
1968 * Q=H1*H2*...*Hk with Householder matrices H. Such a householder matrix can
1969 * be build from a vector u by H=I-(2/u'u)*(u u'). This vectors u are returned
1970 * in the columns of matrix A, overwriting the old content.
1971 * The matrix R has a quadric upper part KxK with values in the upper right
1972 * triangle and zeros in all other elements. Here the diagonal elements of R
1973 * are stored in the vector R and the other upper right elements in the upper
1974 * right of the matrix A.
1975 * The function returns false, if calculation breaks. But because of round-off
1976 * errors singularity is often not detected.
1978 bool lcl_CalculateQRdecomposition(ScMatrixRef pMatA,
1979 ::std::vector< double>& pVecR, SCSIZE nK, SCSIZE nN)
1981 double fScale ;
1982 double fEuclid ;
1983 double fFactor ;
1984 double fSignum ;
1985 double fSum ;
1986 // ScMatrix matrices are zero based, index access (column,row)
1987 for (SCSIZE col = 0; col <nK; col++)
1989 // calculate vector u of the householder transformation
1990 fScale = lcl_GetColumnMaximumNorm(pMatA, col, col, nN);
1991 if (fScale == 0.0)
1993 // A is singular
1994 return false;
1996 for (SCSIZE row = col; row <nN; row++)
1997 pMatA->PutDouble( pMatA->GetDouble(col,row)/fScale, col, row);
1999 fEuclid = lcl_GetColumnEuclideanNorm(pMatA, col, col, nN);
2000 fFactor = 1.0/fEuclid/(fEuclid + fabs(pMatA->GetDouble(col,col)));
2001 fSignum = lcl_GetSign(pMatA->GetDouble(col,col));
2002 pMatA->PutDouble( pMatA->GetDouble(col,col) + fSignum*fEuclid, col,col);
2003 pVecR[col] = -fSignum * fScale * fEuclid;
2005 // apply Householder transformation to A
2006 for (SCSIZE c=col+1; c<nK; c++)
2008 fSum =lcl_GetColumnSumProduct(pMatA, col, pMatA, c, col, nN);
2009 for (SCSIZE row = col; row <nN; row++)
2010 pMatA->PutDouble( pMatA->GetDouble(c,row) - fSum * fFactor * pMatA->GetDouble(col,row), c, row);
2013 return true;
2016 // same with transposed matrix A, N is count of columns, K count of rows
2017 bool lcl_TCalculateQRdecomposition(ScMatrixRef pMatA,
2018 ::std::vector< double>& pVecR, SCSIZE nK, SCSIZE nN)
2020 double fSum ;
2021 // ScMatrix matrices are zero based, index access (column,row)
2022 for (SCSIZE row = 0; row <nK; row++)
2024 // calculate vector u of the householder transformation
2025 const double fScale = lcl_TGetColumnMaximumNorm(pMatA, row, row, nN);
2026 if (fScale == 0.0)
2028 // A is singular
2029 return false;
2031 for (SCSIZE col = row; col <nN; col++)
2032 pMatA->PutDouble( pMatA->GetDouble(col,row)/fScale, col, row);
2034 const double fEuclid = lcl_TGetColumnEuclideanNorm(pMatA, row, row, nN);
2035 const double fFactor = 1.0/fEuclid/(fEuclid + fabs(pMatA->GetDouble(row,row)));
2036 const double fSignum = lcl_GetSign(pMatA->GetDouble(row,row));
2037 pMatA->PutDouble( pMatA->GetDouble(row,row) + fSignum*fEuclid, row,row);
2038 pVecR[row] = -fSignum * fScale * fEuclid;
2040 // apply Householder transformation to A
2041 for (SCSIZE r=row+1; r<nK; r++)
2043 fSum =lcl_TGetColumnSumProduct(pMatA, row, pMatA, r, row, nN);
2044 for (SCSIZE col = row; col <nN; col++)
2045 pMatA->PutDouble(
2046 pMatA->GetDouble(col,r) - fSum * fFactor * pMatA->GetDouble(col,row), col, r);
2049 return true;
2052 /* Applies a Householder transformation to a column vector Y with is given as
2053 * Nx1 Matrix. The Vektor u, from which the Householder transformation is build,
2054 * is the column part in matrix A, with column index C, starting with row
2055 * index C. A is the result of the QR decomposition as obtained from
2056 * lcl_CaluclateQRdecomposition.
2058 void lcl_ApplyHouseholderTransformation(ScMatrixRef pMatA, SCSIZE nC,
2059 ScMatrixRef pMatY, SCSIZE nN)
2061 // ScMatrix matrices are zero based, index access (column,row)
2062 double fDenominator = lcl_GetColumnSumProduct(pMatA, nC, pMatA, nC, nC, nN);
2063 double fNumerator = lcl_GetColumnSumProduct(pMatA, nC, pMatY, 0, nC, nN);
2064 double fFactor = 2.0 * (fNumerator/fDenominator);
2065 for (SCSIZE row = nC; row < nN; row++)
2066 pMatY->PutDouble(
2067 pMatY->GetDouble(row) - fFactor * pMatA->GetDouble(nC,row), row);
2070 // Same with transposed matrices A and Y.
2071 void lcl_TApplyHouseholderTransformation(ScMatrixRef pMatA, SCSIZE nR,
2072 ScMatrixRef pMatY, SCSIZE nN)
2074 // ScMatrix matrices are zero based, index access (column,row)
2075 double fDenominator = lcl_TGetColumnSumProduct(pMatA, nR, pMatA, nR, nR, nN);
2076 double fNumerator = lcl_TGetColumnSumProduct(pMatA, nR, pMatY, 0, nR, nN);
2077 double fFactor = 2.0 * (fNumerator/fDenominator);
2078 for (SCSIZE col = nR; col < nN; col++)
2079 pMatY->PutDouble(
2080 pMatY->GetDouble(col) - fFactor * pMatA->GetDouble(col,nR), col);
2083 /* Solve for X in R*X=S using back substitution. The solution X overwrites S.
2084 * Uses R from the result of the QR decomposition of a NxK matrix A.
2085 * S is a column vector given as matrix, with at least elements on index
2086 * 0 to K-1; elements on index>=K are ignored. Vector R must not have zero
2087 * elements, no check is done.
2089 void lcl_SolveWithUpperRightTriangle(ScMatrixRef pMatA,
2090 ::std::vector< double>& pVecR, ScMatrixRef pMatS,
2091 SCSIZE nK, bool bIsTransposed)
2093 // ScMatrix matrices are zero based, index access (column,row)
2094 SCSIZE row;
2095 // SCSIZE is never negative, therefore test with rowp1=row+1
2096 for (SCSIZE rowp1 = nK; rowp1>0; rowp1--)
2098 row = rowp1-1;
2099 double fSum = pMatS->GetDouble(row);
2100 for (SCSIZE col = rowp1; col<nK ; col++)
2101 if (bIsTransposed)
2102 fSum -= pMatA->GetDouble(row,col) * pMatS->GetDouble(col);
2103 else
2104 fSum -= pMatA->GetDouble(col,row) * pMatS->GetDouble(col);
2105 pMatS->PutDouble( fSum / pVecR[row] , row);
2109 /* Solve for X in R' * X= T using forward substitution. The solution X
2110 * overwrites T. Uses R from the result of the QR decomposition of a NxK
2111 * matrix A. T is a column vectors given as matrix, with at least elements on
2112 * index 0 to K-1; elements on index>=K are ignored. Vector R must not have
2113 * zero elements, no check is done.
2115 void lcl_SolveWithLowerLeftTriangle(ScMatrixRef pMatA,
2116 ::std::vector< double>& pVecR, ScMatrixRef pMatT,
2117 SCSIZE nK, bool bIsTransposed)
2119 // ScMatrix matrices are zero based, index access (column,row)
2120 for (SCSIZE row = 0; row < nK; row++)
2122 double fSum = pMatT -> GetDouble(row);
2123 for (SCSIZE col=0; col < row; col++)
2125 if (bIsTransposed)
2126 fSum -= pMatA->GetDouble(col,row) * pMatT->GetDouble(col);
2127 else
2128 fSum -= pMatA->GetDouble(row,col) * pMatT->GetDouble(col);
2130 pMatT->PutDouble( fSum / pVecR[row] , row);
2134 /* Calculates Z = R * B
2135 * R is given in matrix A and vector VecR as obtained from the QR
2136 * decompostion in lcl_CalculateQRdecomposition. B and Z are column vectors
2137 * given as matrix with at least index 0 to K-1; elements on index>=K are
2138 * not used.
2140 void lcl_ApplyUpperRightTriangle(ScMatrixRef pMatA,
2141 ::std::vector< double>& pVecR, ScMatrixRef pMatB,
2142 ScMatrixRef pMatZ, SCSIZE nK, bool bIsTransposed)
2144 // ScMatrix matrices are zero based, index access (column,row)
2145 for (SCSIZE row = 0; row < nK; row++)
2147 double fSum = pVecR[row] * pMatB->GetDouble(row);
2148 for (SCSIZE col = row+1; col < nK; col++)
2149 if (bIsTransposed)
2150 fSum += pMatA->GetDouble(row,col) * pMatB->GetDouble(col);
2151 else
2152 fSum += pMatA->GetDouble(col,row) * pMatB->GetDouble(col);
2153 pMatZ->PutDouble( fSum, row);
2157 double lcl_GetMeanOverAll(ScMatrixRef pMat, SCSIZE nN)
2159 double fSum = 0.0;
2160 for (SCSIZE i=0 ; i<nN; i++)
2161 fSum += pMat->GetDouble(i);
2162 return fSum/static_cast<double>(nN);
2165 // Calculates means of the columns of matrix X. X is a RxC matrix;
2166 // ResMat is a 1xC matrix (=row).
2167 void lcl_CalculateColumnMeans(ScMatrixRef pX, ScMatrixRef pResMat,
2168 SCSIZE nC, SCSIZE nR)
2170 for (SCSIZE i=0; i < nC; i++)
2172 double fSum =0.0;
2173 for (SCSIZE k=0; k < nR; k++)
2174 fSum += pX->GetDouble(i,k); // GetDouble(Column,Row)
2175 pResMat ->PutDouble( fSum/static_cast<double>(nR),i);
2179 // Calculates means of the rows of matrix X. X is a RxC matrix;
2180 // ResMat is a Rx1 matrix (=column).
2181 void lcl_CalculateRowMeans(ScMatrixRef pX, ScMatrixRef pResMat,
2182 SCSIZE nC, SCSIZE nR)
2184 for (SCSIZE k=0; k < nR; k++)
2186 double fSum = 0.0;
2187 for (SCSIZE i=0; i < nC; i++)
2188 fSum += pX->GetDouble(i,k); // GetDouble(Column,Row)
2189 pResMat ->PutDouble( fSum/static_cast<double>(nC),k);
2193 void lcl_CalculateColumnsDelta(ScMatrixRef pMat, ScMatrixRef pColumnMeans,
2194 SCSIZE nC, SCSIZE nR)
2196 for (SCSIZE i = 0; i < nC; i++)
2197 for (SCSIZE k = 0; k < nR; k++)
2198 pMat->PutDouble( ::rtl::math::approxSub
2199 (pMat->GetDouble(i,k) , pColumnMeans->GetDouble(i) ) , i, k);
2202 void lcl_CalculateRowsDelta(ScMatrixRef pMat, ScMatrixRef pRowMeans,
2203 SCSIZE nC, SCSIZE nR)
2205 for (SCSIZE k = 0; k < nR; k++)
2206 for (SCSIZE i = 0; i < nC; i++)
2207 pMat->PutDouble( ::rtl::math::approxSub
2208 ( pMat->GetDouble(i,k) , pRowMeans->GetDouble(k) ) , i, k);
2211 // Case1 = simple regression
2212 // MatX = X - MeanX, MatY = Y - MeanY, y - haty = (y - MeanY) - (haty - MeanY)
2213 // = (y-MeanY)-((slope*x+a)-(slope*MeanX+a)) = (y-MeanY)-slope*(x-MeanX)
2214 double lcl_GetSSresid(ScMatrixRef pMatX, ScMatrixRef pMatY, double fSlope,
2215 SCSIZE nN)
2217 double fSum = 0.0;
2218 for (SCSIZE i=0; i<nN; i++)
2220 const double fTemp = pMatY->GetDouble(i) - fSlope * pMatX->GetDouble(i);
2221 fSum += fTemp * fTemp;
2223 return fSum;
2228 // Fill default values in matrix X, transform Y to log(Y) in case LOGEST|GROWTH,
2229 // determine sizes of matrices X and Y, determine kind of regression, clone
2230 // Y in case LOGEST|GROWTH, if constant.
2231 bool ScInterpreter::CheckMatrix(bool _bLOG, sal_uInt8& nCase, SCSIZE& nCX,
2232 SCSIZE& nCY, SCSIZE& nRX, SCSIZE& nRY, SCSIZE& M,
2233 SCSIZE& N, ScMatrixRef& pMatX, ScMatrixRef& pMatY)
2236 nCX = 0;
2237 nCY = 0;
2238 nRX = 0;
2239 nRY = 0;
2240 M = 0;
2241 N = 0;
2242 pMatY->GetDimensions(nCY, nRY);
2243 const SCSIZE nCountY = nCY * nRY;
2244 for ( SCSIZE i = 0; i < nCountY; i++ )
2246 if (!pMatY->IsValue(i))
2248 PushIllegalArgument();
2249 return false;
2253 if ( _bLOG )
2255 ScMatrixRef pNewY = pMatY->CloneIfConst();
2256 for (SCSIZE nElem = 0; nElem < nCountY; nElem++)
2258 const double fVal = pNewY->GetDouble(nElem);
2259 if (fVal <= 0.0)
2261 PushIllegalArgument();
2262 return false;
2264 else
2265 pNewY->PutDouble(log(fVal), nElem);
2267 pMatY = pNewY;
2270 if (pMatX)
2272 pMatX->GetDimensions(nCX, nRX);
2273 const SCSIZE nCountX = nCX * nRX;
2274 for ( SCSIZE i = 0; i < nCountX; i++ )
2275 if (!pMatX->IsValue(i))
2277 PushIllegalArgument();
2278 return false;
2280 if (nCX == nCY && nRX == nRY)
2282 nCase = 1; // simple regression
2283 M = 1;
2284 N = nCountY;
2286 else if (nCY != 1 && nRY != 1)
2288 PushIllegalArgument();
2289 return false;
2291 else if (nCY == 1)
2293 if (nRX != nRY)
2295 PushIllegalArgument();
2296 return false;
2298 else
2300 nCase = 2; // Y is column
2301 N = nRY;
2302 M = nCX;
2305 else if (nCX != nCY)
2307 PushIllegalArgument();
2308 return false;
2310 else
2312 nCase = 3; // Y is row
2313 N = nCY;
2314 M = nRX;
2317 else
2319 pMatX = GetNewMat(nCY, nRY);
2320 nCX = nCY;
2321 nRX = nRY;
2322 if (!pMatX)
2324 PushIllegalArgument();
2325 return false;
2327 for ( SCSIZE i = 1; i <= nCountY; i++ )
2328 pMatX->PutDouble(static_cast<double>(i), i-1);
2329 nCase = 1;
2330 N = nCountY;
2331 M = 1;
2333 return true;
2336 // LINEST
2337 void ScInterpreter::ScLinest()
2339 CalculateRGPRKP(false);
2342 // LOGEST
2343 void ScInterpreter::ScLogest()
2345 CalculateRGPRKP(true);
2348 void ScInterpreter::CalculateRGPRKP(bool _bRKP)
2350 sal_uInt8 nParamCount = GetByte();
2351 if (!MustHaveParamCount( nParamCount, 1, 4 ))
2352 return;
2353 bool bConstant, bStats;
2355 // optional forth parameter
2356 if (nParamCount == 4)
2357 bStats = GetBool();
2358 else
2359 bStats = false;
2361 // The third parameter may not be missing in ODF, if the forth parameter
2362 // is present. But Excel allows it with default true, we too.
2363 if (nParamCount >= 3)
2365 if (IsMissing())
2367 Pop();
2368 bConstant = true;
2369 // PushIllegalParameter(); if ODF behavior is desired
2370 // return;
2372 else
2373 bConstant = GetBool();
2375 else
2376 bConstant = true;
2378 ScMatrixRef pMatX;
2379 if (nParamCount >= 2)
2381 if (IsMissing())
2382 { //In ODF1.2 empty second parameter (which is two ;; ) is allowed
2383 Pop();
2384 pMatX = NULL;
2386 else
2388 pMatX = GetMatrix();
2391 else
2392 pMatX = NULL;
2394 ScMatrixRef pMatY;
2395 pMatY = GetMatrix();
2396 if (!pMatY)
2398 PushIllegalParameter();
2399 return;
2402 // 1 = simple; 2 = multiple with Y as column; 3 = multiple with Y as row
2403 sal_uInt8 nCase;
2405 SCSIZE nCX, nCY; // number of columns
2406 SCSIZE nRX, nRY; //number of rows
2407 SCSIZE K = 0, N = 0; // K=number of variables X, N=number of data samples
2408 if (!CheckMatrix(_bRKP,nCase,nCX,nCY,nRX,nRY,K,N,pMatX,pMatY))
2410 PushIllegalParameter();
2411 return;
2414 // Enough data samples?
2415 if ((bConstant && (N<K+1)) || (!bConstant && (N<K)) || (N<1) || (K<1))
2417 PushIllegalParameter();
2418 return;
2421 ScMatrixRef pResMat;
2422 if (bStats)
2423 pResMat = GetNewMat(K+1,5);
2424 else
2425 pResMat = GetNewMat(K+1,1);
2426 if (!pResMat)
2428 PushError(errCodeOverflow);
2429 return;
2431 // Fill unused cells in pResMat; order (column,row)
2432 if (bStats)
2434 for (SCSIZE i=2; i<K+1; i++)
2436 pResMat->PutString(mrStrPool.intern(ScGlobal::GetRscString(STR_NV_STR)), i, 2);
2437 pResMat->PutString(mrStrPool.intern(ScGlobal::GetRscString(STR_NV_STR)), i, 3);
2438 pResMat->PutString(mrStrPool.intern(ScGlobal::GetRscString(STR_NV_STR)), i, 4);
2442 // Uses sum(x-MeanX)^2 and not [sum x^2]-N * MeanX^2 in case bConstant.
2443 // Clone constant matrices, so that Mat = Mat - Mean is possible.
2444 double fMeanY = 0.0;
2445 if (bConstant)
2447 ScMatrixRef pNewX = pMatX->CloneIfConst();
2448 ScMatrixRef pNewY = pMatY->CloneIfConst();
2449 if (!pNewX || !pNewY)
2451 PushError(errCodeOverflow);
2452 return;
2454 pMatX = pNewX;
2455 pMatY = pNewY;
2456 // DeltaY is possible here; DeltaX depends on nCase, so later
2457 fMeanY = lcl_GetMeanOverAll(pMatY, N);
2458 for (SCSIZE i=0; i<N; i++)
2460 pMatY->PutDouble( ::rtl::math::approxSub(pMatY->GetDouble(i),fMeanY), i );
2464 if (nCase==1)
2466 // calculate simple regression
2467 double fMeanX = 0.0;
2468 if (bConstant)
2469 { // Mat = Mat - Mean
2470 fMeanX = lcl_GetMeanOverAll(pMatX, N);
2471 for (SCSIZE i=0; i<N; i++)
2473 pMatX->PutDouble( ::rtl::math::approxSub(pMatX->GetDouble(i),fMeanX), i );
2476 double fSumXY = lcl_GetSumProduct(pMatX,pMatY,N);
2477 double fSumX2 = lcl_GetSumProduct(pMatX,pMatX,N);
2478 if (fSumX2==0.0)
2480 PushNoValue(); // all x-values are identical
2481 return;
2483 double fSlope = fSumXY / fSumX2;
2484 double fIntercept = 0.0;
2485 if (bConstant)
2486 fIntercept = fMeanY - fSlope * fMeanX;
2487 pResMat->PutDouble(_bRKP ? exp(fIntercept) : fIntercept, 1, 0); //order (column,row)
2488 pResMat->PutDouble(_bRKP ? exp(fSlope) : fSlope, 0, 0);
2490 if (bStats)
2492 double fSSreg = fSlope * fSlope * fSumX2;
2493 pResMat->PutDouble(fSSreg, 0, 4);
2495 double fDegreesFreedom =static_cast<double>( (bConstant) ? N-2 : N-1 );
2496 pResMat->PutDouble(fDegreesFreedom, 1, 3);
2498 double fSSresid = lcl_GetSSresid(pMatX,pMatY,fSlope,N);
2499 pResMat->PutDouble(fSSresid, 1, 4);
2501 if (fDegreesFreedom == 0.0 || fSSresid == 0.0 || fSSreg == 0.0)
2502 { // exact fit; test SSreg too, because SSresid might be
2503 // unequal zero due to round of errors
2504 pResMat->PutDouble(0.0, 1, 4); // SSresid
2505 pResMat->PutString(mrStrPool.intern(ScGlobal::GetRscString(STR_NV_STR)), 0, 3); // F
2506 pResMat->PutDouble(0.0, 1, 2); // RMSE
2507 pResMat->PutDouble(0.0, 0, 1); // SigmaSlope
2508 if (bConstant)
2509 pResMat->PutDouble(0.0, 1, 1); //SigmaIntercept
2510 else
2511 pResMat->PutString(mrStrPool.intern(ScGlobal::GetRscString(STR_NV_STR)), 1, 1);
2512 pResMat->PutDouble(1.0, 0, 2); // R^2
2514 else
2516 double fFstatistic = (fSSreg / static_cast<double>(K))
2517 / (fSSresid / fDegreesFreedom);
2518 pResMat->PutDouble(fFstatistic, 0, 3);
2520 // standard error of estimate
2521 double fRMSE = sqrt(fSSresid / fDegreesFreedom);
2522 pResMat->PutDouble(fRMSE, 1, 2);
2524 double fSigmaSlope = fRMSE / sqrt(fSumX2);
2525 pResMat->PutDouble(fSigmaSlope, 0, 1);
2527 if (bConstant)
2529 double fSigmaIntercept = fRMSE
2530 * sqrt(fMeanX*fMeanX/fSumX2 + 1.0/static_cast<double>(N));
2531 pResMat->PutDouble(fSigmaIntercept, 1, 1);
2533 else
2535 pResMat->PutString(mrStrPool.intern(ScGlobal::GetRscString(STR_NV_STR)), 1, 1);
2538 double fR2 = fSSreg / (fSSreg + fSSresid);
2539 pResMat->PutDouble(fR2, 0, 2);
2542 PushMatrix(pResMat);
2544 else // calculate multiple regression;
2546 // Uses a QR decomposition X = QR. The solution B = (X'X)^(-1) * X' * Y
2547 // becomes B = R^(-1) * Q' * Y
2548 if (nCase ==2) // Y is column
2550 ::std::vector< double> aVecR(N); // for QR decomposition
2551 // Enough memory for needed matrices?
2552 ScMatrixRef pMeans = GetNewMat(K, 1); // mean of each column
2553 ScMatrixRef pMatZ; // for Q' * Y , inter alia
2554 if (bStats)
2555 pMatZ = pMatY->Clone(); // Y is used in statistic, keep it
2556 else
2557 pMatZ = pMatY; // Y can be overwritten
2558 ScMatrixRef pSlopes = GetNewMat(1,K); // from b1 to bK
2559 if (!pMeans || !pMatZ || !pSlopes)
2561 PushError(errCodeOverflow);
2562 return;
2564 if (bConstant)
2566 lcl_CalculateColumnMeans(pMatX, pMeans, K, N);
2567 lcl_CalculateColumnsDelta(pMatX, pMeans, K, N);
2569 if (!lcl_CalculateQRdecomposition(pMatX, aVecR, K, N))
2571 PushNoValue();
2572 return;
2574 // Later on we will divide by elements of aVecR, so make sure
2575 // that they aren't zero.
2576 bool bIsSingular=false;
2577 for (SCSIZE row=0; row < K && !bIsSingular; row++)
2578 bIsSingular = bIsSingular || aVecR[row]==0.0;
2579 if (bIsSingular)
2581 PushNoValue();
2582 return;
2584 // Z = Q' Y;
2585 for (SCSIZE col = 0; col < K; col++)
2587 lcl_ApplyHouseholderTransformation(pMatX, col, pMatZ, N);
2589 // B = R^(-1) * Q' * Y <=> B = R^(-1) * Z <=> R * B = Z
2590 // result Z should have zeros for index>=K; if not, ignore values
2591 for (SCSIZE col = 0; col < K ; col++)
2593 pSlopes->PutDouble( pMatZ->GetDouble(col), col);
2595 lcl_SolveWithUpperRightTriangle(pMatX, aVecR, pSlopes, K, false);
2596 double fIntercept = 0.0;
2597 if (bConstant)
2598 fIntercept = fMeanY - lcl_GetSumProduct(pMeans,pSlopes,K);
2599 // Fill first line in result matrix
2600 pResMat->PutDouble(_bRKP ? exp(fIntercept) : fIntercept, K, 0 );
2601 for (SCSIZE i = 0; i < K; i++)
2602 pResMat->PutDouble(_bRKP ? exp(pSlopes->GetDouble(i))
2603 : pSlopes->GetDouble(i) , K-1-i, 0);
2605 if (bStats)
2607 double fSSreg = 0.0;
2608 double fSSresid = 0.0;
2609 // re-use memory of Z;
2610 pMatZ->FillDouble(0.0, 0, 0, 0, N-1);
2611 // Z = R * Slopes
2612 lcl_ApplyUpperRightTriangle(pMatX, aVecR, pSlopes, pMatZ, K, false);
2613 // Z = Q * Z, that is Q * R * Slopes = X * Slopes
2614 for (SCSIZE colp1 = K; colp1 > 0; colp1--)
2616 lcl_ApplyHouseholderTransformation(pMatX, colp1-1, pMatZ,N);
2618 fSSreg =lcl_GetSumProduct(pMatZ, pMatZ, N);
2619 // re-use Y for residuals, Y = Y-Z
2620 for (SCSIZE row = 0; row < N; row++)
2621 pMatY->PutDouble(pMatY->GetDouble(row) - pMatZ->GetDouble(row), row);
2622 fSSresid = lcl_GetSumProduct(pMatY, pMatY, N);
2623 pResMat->PutDouble(fSSreg, 0, 4);
2624 pResMat->PutDouble(fSSresid, 1, 4);
2626 double fDegreesFreedom =static_cast<double>( (bConstant) ? N-K-1 : N-K );
2627 pResMat->PutDouble(fDegreesFreedom, 1, 3);
2629 if (fDegreesFreedom == 0.0 || fSSresid == 0.0 || fSSreg == 0.0)
2630 { // exact fit; incl. observed values Y are identical
2631 pResMat->PutDouble(0.0, 1, 4); // SSresid
2632 // F = (SSreg/K) / (SSresid/df) = #DIV/0!
2633 pResMat->PutString(mrStrPool.intern(ScGlobal::GetRscString(STR_NV_STR)), 0, 3); // F
2634 // RMSE = sqrt(SSresid / df) = sqrt(0 / df) = 0
2635 pResMat->PutDouble(0.0, 1, 2); // RMSE
2636 // SigmaSlope[i] = RMSE * sqrt(matrix[i,i]) = 0 * sqrt(...) = 0
2637 for (SCSIZE i=0; i<K; i++)
2638 pResMat->PutDouble(0.0, K-1-i, 1);
2640 // SigmaIntercept = RMSE * sqrt(...) = 0
2641 if (bConstant)
2642 pResMat->PutDouble(0.0, K, 1); //SigmaIntercept
2643 else
2644 pResMat->PutString(mrStrPool.intern(ScGlobal::GetRscString(STR_NV_STR)), K, 1);
2646 // R^2 = SSreg / (SSreg + SSresid) = 1.0
2647 pResMat->PutDouble(1.0, 0, 2); // R^2
2649 else
2651 double fFstatistic = (fSSreg / static_cast<double>(K))
2652 / (fSSresid / fDegreesFreedom);
2653 pResMat->PutDouble(fFstatistic, 0, 3);
2655 // standard error of estimate = root mean SSE
2656 double fRMSE = sqrt(fSSresid / fDegreesFreedom);
2657 pResMat->PutDouble(fRMSE, 1, 2);
2659 // standard error of slopes
2660 // = RMSE * sqrt(diagonal element of (R' R)^(-1) )
2661 // standard error of intercept
2662 // = RMSE * sqrt( Xmean * (R' R)^(-1) * Xmean' + 1/N)
2663 // (R' R)^(-1) = R^(-1) * (R')^(-1). Do not calculate it as
2664 // a whole matrix, but iterate over unit vectors.
2665 double fSigmaIntercept = 0.0;
2666 double fPart; // for Xmean * single column of (R' R)^(-1)
2667 for (SCSIZE col = 0; col < K; col++)
2669 //re-use memory of MatZ
2670 pMatZ->FillDouble(0.0,0,0,0,K-1); // Z = unit vector e
2671 pMatZ->PutDouble(1.0, col);
2672 //Solve R' * Z = e
2673 lcl_SolveWithLowerLeftTriangle(pMatX, aVecR, pMatZ, K, false);
2674 // Solve R * Znew = Zold
2675 lcl_SolveWithUpperRightTriangle(pMatX, aVecR, pMatZ, K, false);
2676 // now Z is column col in (R' R)^(-1)
2677 double fSigmaSlope = fRMSE * sqrt(pMatZ->GetDouble(col));
2678 pResMat->PutDouble(fSigmaSlope, K-1-col, 1);
2679 // (R' R) ^(-1) is symmetric
2680 if (bConstant)
2682 fPart = lcl_GetSumProduct(pMeans, pMatZ, K);
2683 fSigmaIntercept += fPart * pMeans->GetDouble(col);
2686 if (bConstant)
2688 fSigmaIntercept = fRMSE
2689 * sqrt(fSigmaIntercept + 1.0 / static_cast<double>(N));
2690 pResMat->PutDouble(fSigmaIntercept, K, 1);
2692 else
2694 pResMat->PutString(mrStrPool.intern(ScGlobal::GetRscString(STR_NV_STR)), K, 1);
2697 double fR2 = fSSreg / (fSSreg + fSSresid);
2698 pResMat->PutDouble(fR2, 0, 2);
2701 PushMatrix(pResMat);
2703 else // nCase == 3, Y is row, all matrices are transposed
2705 ::std::vector< double> aVecR(N); // for QR decomposition
2706 // Enough memory for needed matrices?
2707 ScMatrixRef pMeans = GetNewMat(1, K); // mean of each row
2708 ScMatrixRef pMatZ; // for Q' * Y , inter alia
2709 if (bStats)
2710 pMatZ = pMatY->Clone(); // Y is used in statistic, keep it
2711 else
2712 pMatZ = pMatY; // Y can be overwritten
2713 ScMatrixRef pSlopes = GetNewMat(K,1); // from b1 to bK
2714 if (!pMeans || !pMatZ || !pSlopes)
2716 PushError(errCodeOverflow);
2717 return;
2719 if (bConstant)
2721 lcl_CalculateRowMeans(pMatX, pMeans, N, K);
2722 lcl_CalculateRowsDelta(pMatX, pMeans, N, K);
2725 if (!lcl_TCalculateQRdecomposition(pMatX, aVecR, K, N))
2727 PushNoValue();
2728 return;
2731 // Later on we will divide by elements of aVecR, so make sure
2732 // that they aren't zero.
2733 bool bIsSingular=false;
2734 for (SCSIZE row=0; row < K && !bIsSingular; row++)
2735 bIsSingular = bIsSingular || aVecR[row]==0.0;
2736 if (bIsSingular)
2738 PushNoValue();
2739 return;
2741 // Z = Q' Y
2742 for (SCSIZE row = 0; row < K; row++)
2744 lcl_TApplyHouseholderTransformation(pMatX, row, pMatZ, N);
2746 // B = R^(-1) * Q' * Y <=> B = R^(-1) * Z <=> R * B = Z
2747 // result Z should have zeros for index>=K; if not, ignore values
2748 for (SCSIZE col = 0; col < K ; col++)
2750 pSlopes->PutDouble( pMatZ->GetDouble(col), col);
2752 lcl_SolveWithUpperRightTriangle(pMatX, aVecR, pSlopes, K, true);
2753 double fIntercept = 0.0;
2754 if (bConstant)
2755 fIntercept = fMeanY - lcl_GetSumProduct(pMeans,pSlopes,K);
2756 // Fill first line in result matrix
2757 pResMat->PutDouble(_bRKP ? exp(fIntercept) : fIntercept, K, 0 );
2758 for (SCSIZE i = 0; i < K; i++)
2759 pResMat->PutDouble(_bRKP ? exp(pSlopes->GetDouble(i))
2760 : pSlopes->GetDouble(i) , K-1-i, 0);
2762 if (bStats)
2764 double fSSreg = 0.0;
2765 double fSSresid = 0.0;
2766 // re-use memory of Z;
2767 pMatZ->FillDouble(0.0, 0, 0, N-1, 0);
2768 // Z = R * Slopes
2769 lcl_ApplyUpperRightTriangle(pMatX, aVecR, pSlopes, pMatZ, K, true);
2770 // Z = Q * Z, that is Q * R * Slopes = X * Slopes
2771 for (SCSIZE rowp1 = K; rowp1 > 0; rowp1--)
2773 lcl_TApplyHouseholderTransformation(pMatX, rowp1-1, pMatZ,N);
2775 fSSreg =lcl_GetSumProduct(pMatZ, pMatZ, N);
2776 // re-use Y for residuals, Y = Y-Z
2777 for (SCSIZE col = 0; col < N; col++)
2778 pMatY->PutDouble(pMatY->GetDouble(col) - pMatZ->GetDouble(col), col);
2779 fSSresid = lcl_GetSumProduct(pMatY, pMatY, N);
2780 pResMat->PutDouble(fSSreg, 0, 4);
2781 pResMat->PutDouble(fSSresid, 1, 4);
2783 double fDegreesFreedom =static_cast<double>( (bConstant) ? N-K-1 : N-K );
2784 pResMat->PutDouble(fDegreesFreedom, 1, 3);
2786 if (fDegreesFreedom == 0.0 || fSSresid == 0.0 || fSSreg == 0.0)
2787 { // exact fit; incl. case observed values Y are identical
2788 pResMat->PutDouble(0.0, 1, 4); // SSresid
2789 // F = (SSreg/K) / (SSresid/df) = #DIV/0!
2790 pResMat->PutString(mrStrPool.intern(ScGlobal::GetRscString(STR_NV_STR)), 0, 3); // F
2791 // RMSE = sqrt(SSresid / df) = sqrt(0 / df) = 0
2792 pResMat->PutDouble(0.0, 1, 2); // RMSE
2793 // SigmaSlope[i] = RMSE * sqrt(matrix[i,i]) = 0 * sqrt(...) = 0
2794 for (SCSIZE i=0; i<K; i++)
2795 pResMat->PutDouble(0.0, K-1-i, 1);
2797 // SigmaIntercept = RMSE * sqrt(...) = 0
2798 if (bConstant)
2799 pResMat->PutDouble(0.0, K, 1); //SigmaIntercept
2800 else
2801 pResMat->PutString(mrStrPool.intern(ScGlobal::GetRscString(STR_NV_STR)), K, 1);
2803 // R^2 = SSreg / (SSreg + SSresid) = 1.0
2804 pResMat->PutDouble(1.0, 0, 2); // R^2
2806 else
2808 double fFstatistic = (fSSreg / static_cast<double>(K))
2809 / (fSSresid / fDegreesFreedom);
2810 pResMat->PutDouble(fFstatistic, 0, 3);
2812 // standard error of estimate = root mean SSE
2813 double fRMSE = sqrt(fSSresid / fDegreesFreedom);
2814 pResMat->PutDouble(fRMSE, 1, 2);
2816 // standard error of slopes
2817 // = RMSE * sqrt(diagonal element of (R' R)^(-1) )
2818 // standard error of intercept
2819 // = RMSE * sqrt( Xmean * (R' R)^(-1) * Xmean' + 1/N)
2820 // (R' R)^(-1) = R^(-1) * (R')^(-1). Do not calculate it as
2821 // a whole matrix, but iterate over unit vectors.
2822 // (R' R) ^(-1) is symmetric
2823 double fSigmaIntercept = 0.0;
2824 double fPart; // for Xmean * single col of (R' R)^(-1)
2825 for (SCSIZE row = 0; row < K; row++)
2827 //re-use memory of MatZ
2828 pMatZ->FillDouble(0.0,0,0,K-1,0); // Z = unit vector e
2829 pMatZ->PutDouble(1.0, row);
2830 //Solve R' * Z = e
2831 lcl_SolveWithLowerLeftTriangle(pMatX, aVecR, pMatZ, K, true);
2832 // Solve R * Znew = Zold
2833 lcl_SolveWithUpperRightTriangle(pMatX, aVecR, pMatZ, K, true);
2834 // now Z is column col in (R' R)^(-1)
2835 double fSigmaSlope = fRMSE * sqrt(pMatZ->GetDouble(row));
2836 pResMat->PutDouble(fSigmaSlope, K-1-row, 1);
2837 if (bConstant)
2839 fPart = lcl_GetSumProduct(pMeans, pMatZ, K);
2840 fSigmaIntercept += fPart * pMeans->GetDouble(row);
2843 if (bConstant)
2845 fSigmaIntercept = fRMSE
2846 * sqrt(fSigmaIntercept + 1.0 / static_cast<double>(N));
2847 pResMat->PutDouble(fSigmaIntercept, K, 1);
2849 else
2851 pResMat->PutString(mrStrPool.intern(ScGlobal::GetRscString(STR_NV_STR)), K, 1);
2854 double fR2 = fSSreg / (fSSreg + fSSresid);
2855 pResMat->PutDouble(fR2, 0, 2);
2858 PushMatrix(pResMat);
2863 void ScInterpreter::ScTrend()
2865 CalculateTrendGrowth(false);
2868 void ScInterpreter::ScGrowth()
2870 CalculateTrendGrowth(true);
2873 void ScInterpreter::CalculateTrendGrowth(bool _bGrowth)
2875 sal_uInt8 nParamCount = GetByte();
2876 if (!MustHaveParamCount( nParamCount, 1, 4 ))
2877 return;
2879 // optional forth parameter
2880 bool bConstant;
2881 if (nParamCount == 4)
2882 bConstant = GetBool();
2883 else
2884 bConstant = true;
2886 // The third parameter may be missing in ODF, although the forth parameter
2887 // is present. Default values depend on data not yet read.
2888 ScMatrixRef pMatNewX;
2889 if (nParamCount >= 3)
2891 if (IsMissing())
2893 Pop();
2894 pMatNewX = NULL;
2896 else
2897 pMatNewX = GetMatrix();
2899 else
2900 pMatNewX = NULL;
2902 //In ODF1.2 empty second parameter (which is two ;; ) is allowed
2903 //Defaults will be set in CheckMatrix
2904 ScMatrixRef pMatX;
2905 if (nParamCount >= 2)
2907 if (IsMissing())
2909 Pop();
2910 pMatX = NULL;
2912 else
2914 pMatX = GetMatrix();
2917 else
2918 pMatX = NULL;
2920 ScMatrixRef pMatY;
2921 pMatY = GetMatrix();
2922 if (!pMatY)
2924 PushIllegalParameter();
2925 return;
2928 // 1 = simple; 2 = multiple with Y as column; 3 = multiple with Y as row
2929 sal_uInt8 nCase;
2931 SCSIZE nCX, nCY; // number of columns
2932 SCSIZE nRX, nRY; //number of rows
2933 SCSIZE K = 0, N = 0; // K=number of variables X, N=number of data samples
2934 if (!CheckMatrix(_bGrowth,nCase,nCX,nCY,nRX,nRY,K,N,pMatX,pMatY))
2936 PushIllegalParameter();
2937 return;
2940 // Enough data samples?
2941 if ((bConstant && (N<K+1)) || (!bConstant && (N<K)) || (N<1) || (K<1))
2943 PushIllegalParameter();
2944 return;
2947 // Set default pMatNewX if necessary
2948 SCSIZE nCXN, nRXN;
2949 SCSIZE nCountXN;
2950 if (!pMatNewX)
2952 nCXN = nCX;
2953 nRXN = nRX;
2954 nCountXN = nCXN * nRXN;
2955 pMatNewX = pMatX->Clone(); // pMatX will be changed to X-meanX
2957 else
2959 pMatNewX->GetDimensions(nCXN, nRXN);
2960 if ((nCase == 2 && K != nCXN) || (nCase == 3 && K != nRXN))
2962 PushIllegalArgument();
2963 return;
2965 nCountXN = nCXN * nRXN;
2966 for (SCSIZE i = 0; i < nCountXN; i++)
2967 if (!pMatNewX->IsValue(i))
2969 PushIllegalArgument();
2970 return;
2973 ScMatrixRef pResMat; // size depends on nCase
2974 if (nCase == 1)
2975 pResMat = GetNewMat(nCXN,nRXN);
2976 else
2978 if (nCase==2)
2979 pResMat = GetNewMat(1,nRXN);
2980 else
2981 pResMat = GetNewMat(nCXN,1);
2983 if (!pResMat)
2985 PushError(errCodeOverflow);
2986 return;
2988 // Uses sum(x-MeanX)^2 and not [sum x^2]-N * MeanX^2 in case bConstant.
2989 // Clone constant matrices, so that Mat = Mat - Mean is possible.
2990 double fMeanY = 0.0;
2991 if (bConstant)
2993 ScMatrixRef pCopyX = pMatX->CloneIfConst();
2994 ScMatrixRef pCopyY = pMatY->CloneIfConst();
2995 if (!pCopyX || !pCopyY)
2997 PushError(errStackOverflow);
2998 return;
3000 pMatX = pCopyX;
3001 pMatY = pCopyY;
3002 // DeltaY is possible here; DeltaX depends on nCase, so later
3003 fMeanY = lcl_GetMeanOverAll(pMatY, N);
3004 for (SCSIZE i=0; i<N; i++)
3006 pMatY->PutDouble( ::rtl::math::approxSub(pMatY->GetDouble(i),fMeanY), i );
3010 if (nCase==1)
3012 // calculate simple regression
3013 double fMeanX = 0.0;
3014 if (bConstant)
3015 { // Mat = Mat - Mean
3016 fMeanX = lcl_GetMeanOverAll(pMatX, N);
3017 for (SCSIZE i=0; i<N; i++)
3019 pMatX->PutDouble( ::rtl::math::approxSub(pMatX->GetDouble(i),fMeanX), i );
3022 double fSumXY = lcl_GetSumProduct(pMatX,pMatY,N);
3023 double fSumX2 = lcl_GetSumProduct(pMatX,pMatX,N);
3024 if (fSumX2==0.0)
3026 PushNoValue(); // all x-values are identical
3027 return;
3029 double fSlope = fSumXY / fSumX2;
3030 double fHelp;
3031 if (bConstant)
3033 double fIntercept = fMeanY - fSlope * fMeanX;
3034 for (SCSIZE i = 0; i < nCountXN; i++)
3036 fHelp = pMatNewX->GetDouble(i)*fSlope + fIntercept;
3037 pResMat->PutDouble(_bGrowth ? exp(fHelp) : fHelp, i);
3040 else
3042 for (SCSIZE i = 0; i < nCountXN; i++)
3044 fHelp = pMatNewX->GetDouble(i)*fSlope;
3045 pResMat->PutDouble(_bGrowth ? exp(fHelp) : fHelp, i);
3049 else // calculate multiple regression;
3051 if (nCase ==2) // Y is column
3053 ::std::vector< double> aVecR(N); // for QR decomposition
3054 // Enough memory for needed matrices?
3055 ScMatrixRef pMeans = GetNewMat(K, 1); // mean of each column
3056 ScMatrixRef pSlopes = GetNewMat(1,K); // from b1 to bK
3057 if (!pMeans || !pSlopes)
3059 PushError(errCodeOverflow);
3060 return;
3062 if (bConstant)
3064 lcl_CalculateColumnMeans(pMatX, pMeans, K, N);
3065 lcl_CalculateColumnsDelta(pMatX, pMeans, K, N);
3067 if (!lcl_CalculateQRdecomposition(pMatX, aVecR, K, N))
3069 PushNoValue();
3070 return;
3072 // Later on we will divide by elements of aVecR, so make sure
3073 // that they aren't zero.
3074 bool bIsSingular=false;
3075 for (SCSIZE row=0; row < K && !bIsSingular; row++)
3076 bIsSingular = bIsSingular || aVecR[row]==0.0;
3077 if (bIsSingular)
3079 PushNoValue();
3080 return;
3082 // Z := Q' Y; Y is overwritten with result Z
3083 for (SCSIZE col = 0; col < K; col++)
3085 lcl_ApplyHouseholderTransformation(pMatX, col, pMatY, N);
3087 // B = R^(-1) * Q' * Y <=> B = R^(-1) * Z <=> R * B = Z
3088 // result Z should have zeros for index>=K; if not, ignore values
3089 for (SCSIZE col = 0; col < K ; col++)
3091 pSlopes->PutDouble( pMatY->GetDouble(col), col);
3093 lcl_SolveWithUpperRightTriangle(pMatX, aVecR, pSlopes, K, false);
3095 // Fill result matrix
3096 lcl_MFastMult(pMatNewX,pSlopes,pResMat,nRXN,K,1);
3097 if (bConstant)
3099 double fIntercept = fMeanY - lcl_GetSumProduct(pMeans,pSlopes,K);
3100 for (SCSIZE row = 0; row < nRXN; row++)
3101 pResMat->PutDouble(pResMat->GetDouble(row)+fIntercept, row);
3103 if (_bGrowth)
3105 for (SCSIZE i = 0; i < nRXN; i++)
3106 pResMat->PutDouble(exp(pResMat->GetDouble(i)), i);
3109 else
3110 { // nCase == 3, Y is row, all matrices are transposed
3112 ::std::vector< double> aVecR(N); // for QR decomposition
3113 // Enough memory for needed matrices?
3114 ScMatrixRef pMeans = GetNewMat(1, K); // mean of each row
3115 ScMatrixRef pSlopes = GetNewMat(K,1); // row from b1 to bK
3116 if (!pMeans || !pSlopes)
3118 PushError(errCodeOverflow);
3119 return;
3121 if (bConstant)
3123 lcl_CalculateRowMeans(pMatX, pMeans, N, K);
3124 lcl_CalculateRowsDelta(pMatX, pMeans, N, K);
3126 if (!lcl_TCalculateQRdecomposition(pMatX, aVecR, K, N))
3128 PushNoValue();
3129 return;
3131 // Later on we will divide by elements of aVecR, so make sure
3132 // that they aren't zero.
3133 bool bIsSingular=false;
3134 for (SCSIZE row=0; row < K && !bIsSingular; row++)
3135 bIsSingular = bIsSingular || aVecR[row]==0.0;
3136 if (bIsSingular)
3138 PushNoValue();
3139 return;
3141 // Z := Q' Y; Y is overwritten with result Z
3142 for (SCSIZE row = 0; row < K; row++)
3144 lcl_TApplyHouseholderTransformation(pMatX, row, pMatY, N);
3146 // B = R^(-1) * Q' * Y <=> B = R^(-1) * Z <=> R * B = Z
3147 // result Z should have zeros for index>=K; if not, ignore values
3148 for (SCSIZE col = 0; col < K ; col++)
3150 pSlopes->PutDouble( pMatY->GetDouble(col), col);
3152 lcl_SolveWithUpperRightTriangle(pMatX, aVecR, pSlopes, K, true);
3154 // Fill result matrix
3155 lcl_MFastMult(pSlopes,pMatNewX,pResMat,1,K,nCXN);
3156 if (bConstant)
3158 double fIntercept = fMeanY - lcl_GetSumProduct(pMeans,pSlopes,K);
3159 for (SCSIZE col = 0; col < nCXN; col++)
3160 pResMat->PutDouble(pResMat->GetDouble(col)+fIntercept, col);
3162 if (_bGrowth)
3164 for (SCSIZE i = 0; i < nCXN; i++)
3165 pResMat->PutDouble(exp(pResMat->GetDouble(i)), i);
3169 PushMatrix(pResMat);
3172 void ScInterpreter::ScMatRef()
3174 // Falls Deltarefs drin sind...
3175 Push( (FormulaToken&)*pCur );
3176 ScAddress aAdr;
3177 PopSingleRef( aAdr );
3179 ScRefCellValue aCell;
3180 aCell.assign(*pDok, aAdr);
3182 if (aCell.meType != CELLTYPE_FORMULA)
3184 PushError( errNoRef );
3185 return;
3188 const ScMatrix* pMat = aCell.mpFormula->GetMatrix();
3189 if (pMat)
3191 SCSIZE nCols, nRows;
3192 pMat->GetDimensions( nCols, nRows );
3193 SCSIZE nC = static_cast<SCSIZE>(aPos.Col() - aAdr.Col());
3194 SCSIZE nR = static_cast<SCSIZE>(aPos.Row() - aAdr.Row());
3195 if ((nCols <= nC && nCols != 1) || (nRows <= nR && nRows != 1))
3196 PushNA();
3197 else
3199 const ScMatrixValue nMatVal = pMat->Get( nC, nR);
3200 ScMatValType nMatValType = nMatVal.nType;
3202 if (ScMatrix::IsNonValueType( nMatValType))
3204 if (ScMatrix::IsEmptyPathType( nMatValType))
3205 { // result of empty false jump path
3206 nFuncFmtType = css::util::NumberFormat::LOGICAL;
3207 PushInt(0);
3209 else if (ScMatrix::IsEmptyType( nMatValType))
3211 // Not inherited (really?) and display as empty string, not 0.
3212 PushTempToken( new ScEmptyCellToken( false, true));
3214 else
3215 PushString( nMatVal.GetString() );
3217 else
3219 PushDouble(nMatVal.fVal); // handles DoubleError
3220 pDok->GetNumberFormatInfo(nCurFmtType, nCurFmtIndex, aAdr);
3221 nFuncFmtType = nCurFmtType;
3222 nFuncFmtIndex = nCurFmtIndex;
3226 else
3228 // If not a result matrix, obtain the cell value.
3229 sal_uInt16 nErr = aCell.mpFormula->GetErrCode();
3230 if (nErr)
3231 PushError( nErr );
3232 else if (aCell.mpFormula->IsValue())
3233 PushDouble(aCell.mpFormula->GetValue());
3234 else
3236 svl::SharedString aVal = aCell.mpFormula->GetString();
3237 PushString( aVal );
3239 pDok->GetNumberFormatInfo(nCurFmtType, nCurFmtIndex, aAdr);
3240 nFuncFmtType = nCurFmtType;
3241 nFuncFmtIndex = nCurFmtIndex;
3245 void ScInterpreter::ScInfo()
3247 if( MustHaveParamCount( GetByte(), 1 ) )
3249 OUString aStr = GetString().getString();
3250 ScCellKeywordTranslator::transKeyword(aStr, ScGlobal::GetLocale(), ocInfo);
3251 if( aStr == "SYSTEM" )
3252 PushString( OUString( SC_INFO_OSVERSION ) );
3253 else if( aStr == "OSVERSION" )
3254 PushString( OUString( "Windows (32-bit) NT 5.01" ) );
3255 else if( aStr == "RELEASE" )
3256 PushString( ::utl::Bootstrap::getBuildIdData( OUString() ) );
3257 else if( aStr == "NUMFILE" )
3258 PushDouble( 1 );
3259 else if( aStr == "RECALC" )
3260 PushString( ScGlobal::GetRscString( pDok->GetAutoCalc() ? STR_RECALC_AUTO : STR_RECALC_MANUAL ) );
3261 else
3262 PushIllegalArgument();
3266 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */