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