LCOV - code coverage report
Current view: top level - sc/source/core/tool - interpr5.cxx (source / functions) Hit Total Coverage
Test: libreoffice_filtered.info Lines: 231 1606 14.4 %
Date: 2012-08-25 Functions: 17 79 21.5 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 250 3534 7.1 %

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

Generated by: LCOV version 1.10